Dimensionality reduction based analysis of inter-individual vicinity
In order to investigate individual vicinity within sample, we perform a Principal Component Analysis (PCA), which reduces dimensions while keeping maximum of sample variance summarised in āeigenvectorsā (Lever et al, 2017).
We also perform another dimensionality reduction analysis, the Uniform Manifold Approximation and Projection (UMAP), which is complementary to PCA, as it is nonlinear, and outperforms t-SNE (Kobak et al, 2019). A key parameter for the UMAP is the number of neighbours for each individual. In order to determine the most appropriate number of neighbours according to the latent structure of the data, we use the result of the hierarchical clustering of cells, cut at three clusters recapitulating developmental days or cell types relative to the dataset, and apply the mean number of cells per cluster.
dna_pca<-ACP(log2(dna_upm_subset+1))
dna_umap<-make.umap2(log2(dna_upm_subset+1),n_components = 3,n_neighbors = ncol(dna_upm_subset),min_dist = 0.2)#good
rna_pca<-ACP(log2(rna_subset+1))
rna_umap<-make.umap2(log2(rna_subset+1),n_components = 3,n_neighbors = ncol(rna_subset),min_dist = 0.2, metric= "correlation")#good
# save.image("2021_06_07_embryo_umap.RData")
load(file = "2021_06_07_embryo_umap.RData")
dna_pca_fig <- plot_ly(x=dna_pca$x[,"PC1"], y=dna_pca$x[,"PC2"], z=dna_pca$x[,"PC3"],color = ~names(day_colors), colors = day_color_pca_umap,alpha=0.6,scene='scene1')
dna_pca_fig <- dna_pca_fig %>% add_markers()
dna_umap_fig <- plot_ly(x=dna_umap[,1], y=dna_umap[,2], z=dna_umap[,3],color = ~names(day_colors), colors = day_color_pca_umap,alpha=0.6,symbol = ~names(lineage_shape), symbols=lineage_shape_pca_umap,scene='scene2')
dna_umap_fig <- dna_umap_fig %>% add_markers()
dna_pca_umap_fig <- subplot(dna_pca_fig, dna_umap_fig)
dna_pca_umap_fig <- dna_pca_umap_fig %>% layout(title = "3D Subplots",
scene1 = list(domain=list(x=c(0,0.5),y=c(0,1)),
aspectmode='cube'),
scene2 = list(domain=list(x=c(0.5,1),y=c(0,1)),
aspectmode='cube'))
dna_pca_umap_fig
rna_pca_fig <- plot_ly(x=rna_pca$x[,"PC1"], y=rna_pca$x[,"PC2"], z=rna_pca$x[,"PC3"],color = ~names(lineage_colors), colors = lineage_color_pca_umap,alpha=0.6, scene='scene1')
rna_pca_fig <- rna_pca_fig %>% add_markers()
rna_umap_fig <- plot_ly(x=rna_umap[,1], y=rna_umap[,2], z=rna_umap[,3],color = ~names(lineage_colors), colors = lineage_color_pca_umap,alpha=0.6,symbol = ~names(day_shape), symbols=day_shape_pca_umap, scene='scene2')
rna_umap_fig <- rna_umap_fig %>% add_markers()
rna_pca_umap_fig <- subplot(rna_pca_fig, rna_umap_fig)
rna_pca_umap_fig <- rna_pca_umap_fig %>% layout(title = "3D Subplots",
scene1 = list(domain=list(x=c(0,0.5),y=c(0,1)),
aspectmode='cube'),
scene2 = list(domain=list(x=c(0.5,1),y=c(0,1)),
aspectmode='cube'))
rna_pca_umap_fig
# save.image(paste0(timeNow(),"embryo_dna_rna_umap.RData"))
We observe that applying the ācorrelationā metric based on Pearson distance to umap calculation provides much better results than euclidean distance.
PCA and UMAP yield groups of individuals in line with hierarchical clustering. For both analyses, we observe that gene promoter methylation mainly recapitulates developmental progression (embryonic days) while gene expression recapitulates cell lineages(EPI, PE, TE). This observation is in line with previously published results from (Zhou et al, 2019), as shown in the figure below:
āPrincipal component analysis of DNA methylome data showed that these 130 cells formed 4 major clusters (Extended Data Fig. 8g, h), with a combination of the EPI, PE and TE at the blastocyst stage (day 6) as a single cluster, and the EPI, PE and TE beyond the blastocyst stage as another 3 separate clusters, suggesting that all of the 3 lineages showed considerable changes in DNA methylation soon after implantation.ā
In terms of biology, this could mean that at day 6, global DNA methylation state results from epigenetic waves at early embryonic stages, prior to lineage specification. Later stages show rewriting of epigenetic marks specific to cell lineages, which have distinct transcriptomic signatures.
This observation is interesting as a combination of DNA methylation and gene expression levels might allow to assign developmental stage and lineage to single cells of the human embryo.
Network visualization
As they are the main drivers of cell fate progression, we focus on transcription factor interactions. We query the TF2DNA database on computed interactions in human based on DNA binding motives. Transcription factors are preceded with the āTFā symbol and yield a list of regulated genes they interact with, while other classes of genes do not.
# fastWrite(c(module_promoters_epi_d6,module_transcripts_epi_d6),file="module_promoters_module_transcripts_epi_d6.txt",col.names = F)
# fastWrite(c(module_promoters_pe_d8,module_transcripts_pe_d8),file="module_promoters_module_transcripts_pe_d8.txt",col.names = F)
# fastWrite(c(module_promoters_te_d6,module_transcripts_te_d6),file="module_promoters_module_transcripts_te_d6.txt",col.names = F)
epi_interaction_files = list.files(pattern="^epi_d6_*")
sub1=sub("^[epi_d6_]+(*)", "\\1", epi_interaction_files)
sub2=sub("\\.csv.*", "", sub1)
epi_module_interactions = lapply(epi_interaction_files, fastRead2)
names(epi_module_interactions)=sub2
pe_interaction_files = list.files(pattern="^pe_d8_*")
sub1=sub("^[pe_d8_]+(*)", "\\1", pe_interaction_files)
sub2=sub("\\.csv.*", "", sub1)
pe_module_interactions = lapply(pe_interaction_files, fastRead2)
names(pe_module_interactions)=sub2
te_interaction_files = list.files(pattern="^te_d6_*")
sub1=sub("^[te_d6_]+(*)", "\\1", te_interaction_files)
sub2=sub("\\.csv.*", "", sub1)
te_module_interactions = lapply(te_interaction_files, fastRead2)
names(te_module_interactions)=sub2
epi_d6_dna_rna_module_interaction=NULL
epi_d6_interaction_df=NULL
for (i in names(epi_module_interactions)){
epi_d6_dna_rna_module_interaction[[i]]=cbind(source_node=rep(names(epi_module_interactions[i]),nrow(epi_module_interactions[[i]])),target_node=rownames(epi_module_interactions[[i]]),p_value=epi_module_interactions[[i]]$p_value,chromosome=epi_module_interactions[[i]]$chromosome_name,downstream_gene=epi_module_interactions[[i]]$downstream)
epi_d6_interaction_df=rbind(epi_d6_interaction_df,epi_d6_dna_rna_module_interaction[[i]])
}
pe_d8_dna_rna_module_interaction=NULL
pe_d8_interaction_df=NULL
for (i in names(pe_module_interactions)){
pe_d8_dna_rna_module_interaction[[i]]=cbind(source_node=rep(names(pe_module_interactions[i]),nrow(pe_module_interactions[[i]])),target_node=rownames(pe_module_interactions[[i]]),p_value=pe_module_interactions[[i]]$p_value,chromosome=pe_module_interactions[[i]]$chromosome_name,downstream_gene=pe_module_interactions[[i]]$downstream)
pe_d8_interaction_df=rbind(pe_d8_interaction_df,pe_d8_dna_rna_module_interaction[[i]])
}
te_d6_dna_rna_module_interaction=NULL
te_d6_interaction_df=NULL
for (i in names(te_module_interactions)){
te_d6_dna_rna_module_interaction[[i]]=cbind(source_node=rep(names(te_module_interactions[i]),nrow(te_module_interactions[[i]])),target_node=rownames(te_module_interactions[[i]]),p_value=te_module_interactions[[i]]$p_value,chromosome=te_module_interactions[[i]]$chromosome_name,downstream_gene=te_module_interactions[[i]]$downstream)
te_d6_interaction_df=rbind(te_d6_interaction_df,te_d6_dna_rna_module_interaction[[i]])
}
epi_d6_dna_adjacency <- adjacency(wgcna_datExpr[["dna"]],
selectCols = NULL,
type = "signed",
power = 12, #set soft-power to 12 as for module computation
corFnc = "cor", corOptions = list(use = "p"),
weights = NULL,
distFnc = "dist", distOptions = "method = 'ward.D2'",
weightArgNames = c("weights.x", "weights.y"))
epi_d6_rna_adjacency <- adjacency(wgcna_datExpr[["rna"]],
selectCols = NULL,
type = "signed",
power = 12, #set soft-power to 12 as for module computation
corFnc = "cor", corOptions = list(use = "p"),
weights = NULL,
distFnc = "dist", distOptions = "method = 'ward.D2'",
weightArgNames = c("weights.x", "weights.y"))
pe_d8_dna_adjacency <- adjacency(wgcna_datExpr[["dna"]],
selectCols = NULL,
type = "signed",
power = 12, #set soft-power to 12 as for module computation
corFnc = "cor", corOptions = list(use = "p"),
weights = NULL,
distFnc = "dist", distOptions = "method = 'ward.D2'",
weightArgNames = c("weights.x", "weights.y"))
pe_d8_rna_adjacency <- adjacency(wgcna_datExpr[["rna"]],
selectCols = NULL,
type = "signed",
power = 12, #set soft-power to 12 as for module computation
corFnc = "cor", corOptions = list(use = "p"),
weights = NULL,
distFnc = "dist", distOptions = "method = 'ward.D2'",
weightArgNames = c("weights.x", "weights.y"))
te_d6_dna_adjacency <- adjacency(wgcna_datExpr[["dna"]],
selectCols = NULL,
type = "signed",
power = 12, #set soft-power to 12 as for module computation
corFnc = "cor", corOptions = list(use = "p"),
weights = NULL,
distFnc = "dist", distOptions = "method = 'ward.D2'",
weightArgNames = c("weights.x", "weights.y"))
te_d6_rna_adjacency <- adjacency(wgcna_datExpr[["rna"]],
selectCols = NULL,
type = "signed",
power = 12, #set soft-power to 12 as for module computation
corFnc = "cor", corOptions = list(use = "p"),
weights = NULL,
distFnc = "dist", distOptions = "method = 'ward.D2'",
weightArgNames = c("weights.x", "weights.y"))
epi_d6_dna_adjacency_selected=epi_d6_dna_adjacency[module_promoters_epi_d6,module_promoters_epi_d6]
epi_d6_rna_adjacency_selected=epi_d6_rna_adjacency[module_transcripts_epi_d6,module_transcripts_epi_d6]
pe_d8_dna_adjacency_selected=pe_d8_dna_adjacency[module_promoters_pe_d8,module_promoters_pe_d8]
pe_d8_rna_adjacency_selected=pe_d8_rna_adjacency[module_transcripts_pe_d8,module_transcripts_pe_d8]
te_d6_dna_adjacency_selected=te_d6_dna_adjacency[module_promoters_te_d6,module_promoters_te_d6]
te_d6_rna_adjacency_selected=te_d6_rna_adjacency[module_transcripts_te_d6,module_transcripts_te_d6]
module_promoters_epi_d6_coord=NULL
module_promoters_epi_d6_coord$source_node=module_promoters_epi_d6
module_promoters_epi_d6_coord$x_source=rep(1,length(module_promoters_epi_d6))
module_promoters_epi_d6_coord$y_source=seq(to=(100/length(module_promoters_epi_d6)), from=100, by=-(100/length(module_promoters_epi_d6)))
module_promoters_epi_d6_coord=as.data.frame(module_promoters_epi_d6_coord,col.names=names(module_promoters_epi_d6_coord))
module_transcripts_epi_d6_coord=NULL
module_transcripts_epi_d6_coord$source_node=module_transcripts_epi_d6
module_transcripts_epi_d6_coord$x_source=rep(2,length(module_transcripts_epi_d6))
module_transcripts_epi_d6_coord$y_source=seq(to=(100/length(module_transcripts_epi_d6)), from=100, by=-(100/length(module_transcripts_epi_d6)))
module_transcripts_epi_d6_coord=as.data.frame(module_transcripts_epi_d6_coord,col.names=names(module_transcripts_epi_d6_coord))
epi_modules_coord=rbind(module_promoters_epi_d6_coord,module_transcripts_epi_d6_coord)
epi_d6_module_arrows=NULL
epi_arrow_dna_dna=epi_d6_interaction_df[epi_d6_interaction_df[,"source_node"]%in%module_promoters_epi_d6 & epi_d6_interaction_df[,"target_node"]%in%module_promoters_epi_d6,]
epi_arrow_dna_dna=cbind(epi_arrow_dna_dna,x_arrow=rep(1.13,nrow(epi_arrow_dna_dna)),xend_arrow=rep(1.13,nrow(epi_arrow_dna_dna)))
y=NULL
for (i in epi_arrow_dna_dna[,"source_node"]){
y=c(y,module_promoters_epi_d6_coord$y_source[module_promoters_epi_d6_coord$source_node==i])
}
yend=NULL
for (i in epi_arrow_dna_dna[,"target_node"]){
yend=c(yend,module_promoters_epi_d6_coord$y_source[module_promoters_epi_d6_coord$source_node==i])
}
epi_arrow_dna_dna=cbind(epi_arrow_dna_dna,y_arrow=y,yend_arrow=yend)
epi_arrow_dna_rna=epi_d6_interaction_df[epi_d6_interaction_df[,"source_node"]%in%module_promoters_epi_d6 & epi_d6_interaction_df[,"target_node"]%in%module_transcripts_epi_d6,]
epi_arrow_dna_rna=cbind(epi_arrow_dna_rna,x_arrow=rep(1.13,nrow(epi_arrow_dna_rna)),xend_arrow=rep(1.98,nrow(epi_arrow_dna_rna)))
y=NULL
for (i in epi_arrow_dna_rna[,"source_node"]){
y=c(y,module_promoters_epi_d6_coord$y_source[module_promoters_epi_d6_coord$source_node==i])
}
yend=NULL
for (i in epi_arrow_dna_rna[,"target_node"]){
yend=c(yend,module_transcripts_epi_d6_coord$y_source[module_transcripts_epi_d6_coord$source_node==i])
}
epi_arrow_dna_rna=cbind(epi_arrow_dna_rna,y_arrow=y,yend_arrow=yend)
epi_arrow_rna_rna=epi_d6_interaction_df[epi_d6_interaction_df[,"source_node"]%in%module_transcripts_epi_d6 & epi_d6_interaction_df[,"target_node"]%in%module_transcripts_epi_d6,]
epi_arrow_rna_rna=cbind(epi_arrow_rna_rna,x_arrow=rep(1.98,nrow(epi_arrow_rna_rna)),xend_arrow=rep(1.98,nrow(epi_arrow_rna_rna)))
y=NULL
for (i in epi_arrow_rna_rna[,"source_node"]){
y=c(y,module_transcripts_epi_d6_coord$y_source[module_transcripts_epi_d6_coord$source_node==i])
}
yend=NULL
for (i in epi_arrow_rna_rna[,"target_node"]){
yend=c(yend,module_transcripts_epi_d6_coord$y_source[module_transcripts_epi_d6_coord$source_node==i])
}
epi_arrow_rna_rna=cbind(epi_arrow_rna_rna,y_arrow=y,yend_arrow=yend)
epi_arrow_rna_dna=epi_d6_interaction_df[epi_d6_interaction_df[,"source_node"]%in%module_transcripts_epi_d6 & epi_d6_interaction_df[,"target_node"]%in%module_promoters_epi_d6,]
epi_arrow_rna_dna=cbind(epi_arrow_rna_dna,x_arrow=rep(1.98,nrow(epi_arrow_rna_dna)),xend_arrow=rep(1.13,nrow(epi_arrow_rna_dna)))
y=NULL
for (i in epi_arrow_rna_dna[,"source_node"]){
y=c(y,module_transcripts_epi_d6_coord$y_source[module_transcripts_epi_d6_coord$source_node==i])
}
yend=NULL
for (i in epi_arrow_rna_dna[,"target_node"]){
yend=c(yend,module_promoters_epi_d6_coord$y_source[module_promoters_epi_d6_coord$source_node==i])
}
epi_arrow_rna_dna=cbind(epi_arrow_rna_dna,y_arrow=y,yend_arrow=yend)
epi_interaction_arrows=rbind(epi_arrow_dna_dna,epi_arrow_dna_rna,epi_arrow_rna_rna,epi_arrow_rna_dna)
epi_modules_coord$module=ifelse(epi_modules_coord$x_source==1,"dna","rna")
epi_interaction_arrows=cbind(epi_interaction_arrows,module_origin=ifelse(epi_interaction_arrows[,"x_arrow"]==1.13,"dna","rna"))
epi_modules_interaction_plot=ggplot(epi_modules_coord,aes(x=x_source, y=y_source, label=source_node))+
geom_text(aes(label=source_node, color=as.character(module)),hjust=0,vjust=0)+
geom_point(aes(x = ifelse(x_source==1,1.13,1.98),y=y_source, color=as.character(module)))+
geom_curve(data=as.data.frame(epi_interaction_arrows),mapping=aes(x=as.numeric(epi_interaction_arrows[,"x_arrow"]),y=as.numeric(epi_interaction_arrows[,"y_arrow"]),xend=as.numeric(epi_interaction_arrows[,"xend_arrow"]),yend=as.numeric(epi_interaction_arrows[,"yend_arrow"]),color=as.character(epi_interaction_arrows[,"module_origin"])), curvature = -0.2, arrow=arrow(), size=1)+
scale_color_manual(values=c("#13d370","purple"))
module_promoters_pe_d8_coord=NULL
module_promoters_pe_d8_coord$source_node=module_promoters_pe_d8
module_promoters_pe_d8_coord$x_source=rep(1,length(module_promoters_pe_d8))
module_promoters_pe_d8_coord$y_source=seq(to=(100/length(module_promoters_pe_d8)), from=100, by=-(100/length(module_promoters_pe_d8)))
module_promoters_pe_d8_coord=as.data.frame(module_promoters_pe_d8_coord,col.names=names(module_promoters_pe_d8_coord))
module_transcripts_pe_d8_coord=NULL
module_transcripts_pe_d8_coord$source_node=module_transcripts_pe_d8
module_transcripts_pe_d8_coord$x_source=rep(2,length(module_transcripts_pe_d8))
module_transcripts_pe_d8_coord$y_source=seq(to=(100/length(module_transcripts_pe_d8)), from=100, by=-(100/length(module_transcripts_pe_d8)))
module_transcripts_pe_d8_coord=as.data.frame(module_transcripts_pe_d8_coord,col.names=names(module_transcripts_pe_d8_coord))
pe_modules_coord=rbind(module_promoters_pe_d8_coord,module_transcripts_pe_d8_coord)
pe_d8_module_arrows=NULL
pe_arrow_dna_dna=pe_d8_interaction_df[pe_d8_interaction_df[,"source_node"]%in%module_promoters_pe_d8 & pe_d8_interaction_df[,"target_node"]%in%module_promoters_pe_d8,]
pe_arrow_dna_dna=cbind(pe_arrow_dna_dna,x_arrow=rep(1.13,nrow(pe_arrow_dna_dna)),xend_arrow=rep(1.13,nrow(pe_arrow_dna_dna)))
y=NULL
for (i in pe_arrow_dna_dna[,"source_node"]){
y=c(y,module_promoters_pe_d8_coord$y_source[module_promoters_pe_d8_coord$source_node==i])
}
yend=NULL
for (i in pe_arrow_dna_dna[,"target_node"]){
yend=c(yend,module_promoters_pe_d8_coord$y_source[module_promoters_pe_d8_coord$source_node==i])
}
pe_arrow_dna_dna=cbind(pe_arrow_dna_dna,y_arrow=y,yend_arrow=yend)
pe_arrow_dna_rna=pe_d8_interaction_df[pe_d8_interaction_df[,"source_node"]%in%module_promoters_pe_d8 & pe_d8_interaction_df[,"target_node"]%in%module_transcripts_pe_d8,]
pe_arrow_dna_rna=cbind(pe_arrow_dna_rna,x_arrow=rep(1.13,nrow(pe_arrow_dna_rna)),xend_arrow=rep(1.98,nrow(pe_arrow_dna_rna)))
y=NULL
for (i in pe_arrow_dna_rna[,"source_node"]){
y=c(y,module_promoters_pe_d8_coord$y_source[module_promoters_pe_d8_coord$source_node==i])
}
yend=NULL
for (i in pe_arrow_dna_rna[,"target_node"]){
yend=c(yend,module_transcripts_pe_d8_coord$y_source[module_transcripts_pe_d8_coord$source_node==i])
}
pe_arrow_dna_rna=cbind(pe_arrow_dna_rna,y_arrow=y,yend_arrow=yend)
pe_arrow_rna_rna=pe_d8_interaction_df[pe_d8_interaction_df[,"source_node"]%in%module_transcripts_pe_d8 & pe_d8_interaction_df[,"target_node"]%in%module_transcripts_pe_d8,]
pe_arrow_rna_rna=cbind(pe_arrow_rna_rna,x_arrow=rep(1.98,nrow(pe_arrow_rna_rna)),xend_arrow=rep(1.98,nrow(pe_arrow_rna_rna)))
y=NULL
for (i in pe_arrow_rna_rna[,"source_node"]){
y=c(y,module_transcripts_pe_d8_coord$y_source[module_transcripts_pe_d8_coord$source_node==i])
}
yend=NULL
for (i in pe_arrow_rna_rna[,"target_node"]){
yend=c(yend,module_transcripts_pe_d8_coord$y_source[module_transcripts_pe_d8_coord$source_node==i])
}
pe_arrow_rna_rna=cbind(pe_arrow_rna_rna,y_arrow=y,yend_arrow=yend)
pe_arrow_rna_dna=pe_d8_interaction_df[pe_d8_interaction_df[,"source_node"]%in%module_transcripts_pe_d8 & pe_d8_interaction_df[,"target_node"]%in%module_promoters_pe_d8,]
pe_arrow_rna_dna=cbind(pe_arrow_rna_dna,x_arrow=rep(1.98,nrow(pe_arrow_rna_dna)),xend_arrow=rep(1.13,nrow(pe_arrow_rna_dna)))
y=NULL
for (i in pe_arrow_rna_dna[,"source_node"]){
y=c(y,module_transcripts_pe_d8_coord$y_source[module_transcripts_pe_d8_coord$source_node==i])
}
yend=NULL
for (i in pe_arrow_rna_dna[,"target_node"]){
yend=c(yend,module_promoters_pe_d8_coord$y_source[module_promoters_pe_d8_coord$source_node==i])
}
pe_arrow_rna_dna=cbind(pe_arrow_rna_dna,y_arrow=y,yend_arrow=yend)
pe_interaction_arrows=rbind(pe_arrow_dna_dna,pe_arrow_dna_rna,pe_arrow_rna_rna,pe_arrow_rna_dna)
pe_modules_coord$module=ifelse(pe_modules_coord$x_source==1,"dna","rna")
pe_interaction_arrows=cbind(pe_interaction_arrows,module_origin=ifelse(pe_interaction_arrows[,"x_arrow"]==1.13,"dna","rna"))
pe_modules_interaction_plot=ggplot(pe_modules_coord,aes(x=x_source, y=y_source, label=source_node))+
geom_text(aes(label=source_node, color=as.character(module)),hjust=0,vjust=0)+
geom_point(aes(x = ifelse(x_source==1,1.13,1.98),y=y_source, color=as.character(module)))+
geom_curve(data=as.data.frame(pe_interaction_arrows),mapping=aes(x=as.numeric(pe_interaction_arrows[,"x_arrow"]),y=as.numeric(pe_interaction_arrows[,"y_arrow"]),xend=as.numeric(pe_interaction_arrows[,"xend_arrow"]),yend=as.numeric(pe_interaction_arrows[,"yend_arrow"]),color=as.character(pe_interaction_arrows[,"module_origin"])), curvature = -0.2, arrow=arrow(), size=1)+
scale_color_manual(values=c("#13d370","purple"))
module_promoters_te_d6_coord=NULL
module_promoters_te_d6_coord$source_node=module_promoters_te_d6
module_promoters_te_d6_coord$x_source=rep(1,length(module_promoters_te_d6))
module_promoters_te_d6_coord$y_source=seq(to=(100/length(module_promoters_te_d6)), from=100, by=-(100/length(module_promoters_te_d6)))
module_promoters_te_d6_coord=as.data.frame(module_promoters_te_d6_coord,col.names=names(module_promoters_te_d6_coord))
module_transcripts_te_d6_coord=NULL
module_transcripts_te_d6_coord$source_node=module_transcripts_te_d6
module_transcripts_te_d6_coord$x_source=rep(2,length(module_transcripts_te_d6))
module_transcripts_te_d6_coord$y_source=seq(to=(100/length(module_transcripts_te_d6)), from=100, by=-(100/length(module_transcripts_te_d6)))
module_transcripts_te_d6_coord=as.data.frame(module_transcripts_te_d6_coord,col.names=names(module_transcripts_te_d6_coord))
te_modules_coord=rbind(module_promoters_te_d6_coord,module_transcripts_te_d6_coord)
te_d6_module_arrows=NULL
te_arrow_dna_dna=te_d6_interaction_df[te_d6_interaction_df[,"source_node"]%in%module_promoters_te_d6 & te_d6_interaction_df[,"target_node"]%in%module_promoters_te_d6,]
te_arrow_dna_dna=cbind(te_arrow_dna_dna,x_arrow=rep(1.13,nrow(te_arrow_dna_dna)),xend_arrow=rep(1.13,nrow(te_arrow_dna_dna)))
y=NULL
for (i in te_arrow_dna_dna[,"source_node"]){
y=c(y,module_promoters_te_d6_coord$y_source[module_promoters_te_d6_coord$source_node==i])
}
yend=NULL
for (i in te_arrow_dna_dna[,"target_node"]){
yend=c(yend,module_promoters_te_d6_coord$y_source[module_promoters_te_d6_coord$source_node==i])
}
te_arrow_dna_dna=cbind(te_arrow_dna_dna,y_arrow=y,yend_arrow=yend)
te_arrow_dna_rna=te_d6_interaction_df[te_d6_interaction_df[,"source_node"]%in%module_promoters_te_d6 & te_d6_interaction_df[,"target_node"]%in%module_transcripts_te_d6,]
te_arrow_dna_rna=cbind(te_arrow_dna_rna,x_arrow=rep(1.13,nrow(te_arrow_dna_rna)),xend_arrow=rep(1.98,nrow(te_arrow_dna_rna)))
y=NULL
for (i in te_arrow_dna_rna[,"source_node"]){
y=c(y,module_promoters_te_d6_coord$y_source[module_promoters_te_d6_coord$source_node==i])
}
yend=NULL
for (i in te_arrow_dna_rna[,"target_node"]){
yend=c(yend,module_transcripts_te_d6_coord$y_source[module_transcripts_te_d6_coord$source_node==i])
}
te_arrow_dna_rna=cbind(te_arrow_dna_rna,y_arrow=y,yend_arrow=yend)
te_arrow_rna_rna=te_d6_interaction_df[te_d6_interaction_df[,"source_node"]%in%module_transcripts_te_d6 & te_d6_interaction_df[,"target_node"]%in%module_transcripts_te_d6,]
te_arrow_rna_rna=cbind(te_arrow_rna_rna,x_arrow=rep(1.98,nrow(te_arrow_rna_rna)),xend_arrow=rep(1.98,nrow(te_arrow_rna_rna)))
y=NULL
for (i in te_arrow_rna_rna[,"source_node"]){
y=c(y,module_transcripts_te_d6_coord$y_source[module_transcripts_te_d6_coord$source_node==i])
}
yend=NULL
for (i in te_arrow_rna_rna[,"target_node"]){
yend=c(yend,module_transcripts_te_d6_coord$y_source[module_transcripts_te_d6_coord$source_node==i])
}
te_arrow_rna_rna=cbind(te_arrow_rna_rna,y_arrow=y,yend_arrow=yend)
te_arrow_rna_dna=te_d6_interaction_df[te_d6_interaction_df[,"source_node"]%in%module_transcripts_te_d6 & te_d6_interaction_df[,"target_node"]%in%module_promoters_te_d6,]
te_arrow_rna_dna=cbind(te_arrow_rna_dna,x_arrow=rep(1.98,nrow(te_arrow_rna_dna)),xend_arrow=rep(1.13,nrow(te_arrow_rna_dna)))
y=NULL
for (i in te_arrow_rna_dna[,"source_node"]){
y=c(y,module_transcripts_te_d6_coord$y_source[module_transcripts_te_d6_coord$source_node==i])
}
yend=NULL
for (i in te_arrow_rna_dna[,"target_node"]){
yend=c(yend,module_promoters_te_d6_coord$y_source[module_promoters_te_d6_coord$source_node==i])
}
te_arrow_rna_dna=cbind(te_arrow_rna_dna,y_arrow=y,yend_arrow=yend)
te_interaction_arrows=rbind(te_arrow_dna_dna,te_arrow_dna_rna,te_arrow_rna_rna,te_arrow_rna_dna)
te_modules_coord$module=ifelse(te_modules_coord$x_source==1,"dna","rna")
te_interaction_arrows=cbind(te_interaction_arrows,module_origin=ifelse(te_interaction_arrows[,"x_arrow"]==1.13,"dna","rna"))
te_modules_interaction_plot=ggplot(te_modules_coord,aes(x=x_source, y=y_source, label=source_node))+
geom_text(aes(label=source_node, color=as.character(module)),hjust=0,vjust=0)+
geom_point(aes(x = ifelse(x_source==1,1.13,1.98),y=y_source, color=as.character(module)))+
geom_curve(data=as.data.frame(te_interaction_arrows),mapping=aes(x=as.numeric(te_interaction_arrows[,"x_arrow"]),y=as.numeric(te_interaction_arrows[,"y_arrow"]),xend=as.numeric(te_interaction_arrows[,"xend_arrow"]),yend=as.numeric(te_interaction_arrows[,"yend_arrow"]),color=as.character(te_interaction_arrows[,"module_origin"])), curvature = -0.2, arrow=arrow(), size=1)+
scale_color_manual(values=c("#13d370","purple"))
epi_d6_dna_size = NULL
for (i in module_promoters_epi_d6){
epi_d6_dna_size=c(epi_d6_dna_size,sum(epi_interaction_arrows[,"source_node"]==i))
}
names(epi_d6_dna_size)=module_promoters_epi_d6
epi_d6_rna_size = NULL
for (i in module_transcripts_epi_d6){
epi_d6_rna_size=c(epi_d6_rna_size,sum(epi_interaction_arrows[,"source_node"]==i))
}
names(epi_d6_rna_size)=module_transcripts_epi_d6
pe_d8_dna_size = NULL
for (i in module_promoters_pe_d8){
pe_d8_dna_size=c(pe_d8_dna_size,sum(pe_interaction_arrows[,"source_node"]==i))
}
names(pe_d8_dna_size)=module_promoters_pe_d8
pe_d8_rna_size = NULL
for (i in module_transcripts_pe_d8){
pe_d8_rna_size=c(pe_d8_rna_size,sum(pe_interaction_arrows[,"source_node"]==i))
}
names(pe_d8_rna_size)=module_transcripts_pe_d8
te_d6_dna_size = NULL
for (i in module_promoters_te_d6){
te_d6_dna_size=c(te_d6_dna_size,sum(te_interaction_arrows[,"source_node"]==i))
}
names(te_d6_dna_size)=module_promoters_te_d6
te_d6_rna_size = NULL
for (i in module_transcripts_te_d6){
te_d6_rna_size=c(te_d6_rna_size,sum(te_interaction_arrows[,"source_node"]==i))
}
names(te_d6_rna_size)=module_transcripts_te_d6
# save.image("2021_06_14_network.RData")
load("2021_06_14_network.RData")
epi_d6_dna_module_acp=ACP(ifelse(epi_d6_dna_adjacency_selected>median(epi_d6_dna_adjacency_selected),1,0))
epi_d6_rna_module_acp=ACP(ifelse(epi_d6_rna_adjacency_selected>median(epi_d6_rna_adjacency_selected),1,0))
pe_d8_dna_module_acp=ACP(ifelse(pe_d8_dna_adjacency_selected>median(pe_d8_dna_adjacency_selected),1,0))
pe_d8_rna_module_acp=ACP(ifelse(pe_d8_rna_adjacency_selected>median(pe_d8_rna_adjacency_selected),1,0))
te_d6_dna_module_acp=ACP(ifelse(te_d6_dna_adjacency_selected>median(te_d6_dna_adjacency_selected),1,0))
te_d6_rna_module_acp=ACP(ifelse(te_d6_rna_adjacency_selected>median(te_d6_rna_adjacency_selected),1,0))
epi_d6_module_3d_arrows=NULL
epi_3d_arrow_dna_dna=epi_d6_interaction_df[epi_d6_interaction_df[,"source_node"]%in%module_promoters_epi_d6 & epi_d6_interaction_df[,"target_node"]%in%module_promoters_epi_d6,c("source_node","target_node")]
xyz=NULL
for (i in epi_3d_arrow_dna_dna[,"source_node"]){
xyz=rbind(xyz,epi_d6_dna_module_acp$x[rownames(epi_d6_dna_module_acp$x)==i,c(1:3)])
}
xyz_end=NULL
for (i in epi_3d_arrow_dna_dna[,"target_node"]){
xyz_end=rbind(xyz_end,epi_d6_dna_module_acp$x[rownames(epi_d6_dna_module_acp$x)==i,c(1:3)])
}
epi_dna_dna_3d_arrows=data.frame(epi_3d_arrow_dna_dna,x_3d_arrow=xyz[,1],y_3d_arrow=xyz[,2], z_3d_arrow=xyz[,3],xend_3d_arrow=xyz_end[,1],yend_3d_arrow=xyz_end[,2],zend_3d_arrow=xyz_end[,3])
pe_d8_module_3d_arrows=NULL
pe_3d_arrow_dna_dna=pe_d8_interaction_df[pe_d8_interaction_df[,"source_node"]%in%module_promoters_pe_d8 & pe_d8_interaction_df[,"target_node"]%in%module_promoters_pe_d8,c("source_node","target_node")]
xyz=NULL
for (i in pe_3d_arrow_dna_dna[,"source_node"]){
xyz=rbind(xyz,pe_d8_dna_module_acp$x[rownames(pe_d8_dna_module_acp$x)==i,c(1:3)])
}
xyz_end=NULL
for (i in pe_3d_arrow_dna_dna[,"target_node"]){
xyz_end=rbind(xyz_end,pe_d8_dna_module_acp$x[rownames(pe_d8_dna_module_acp$x)==i,c(1:3)])
}
pe_dna_dna_3d_arrows=data.frame(pe_3d_arrow_dna_dna,x_3d_arrow=xyz[,1],y_3d_arrow=xyz[,2], z_3d_arrow=xyz[,3],xend_3d_arrow=xyz_end[,1],yend_3d_arrow=xyz_end[,2],zend_3d_arrow=xyz_end[,3])
te_d6_module_3d_arrows=NULL
te_3d_arrow_dna_dna=te_d6_interaction_df[te_d6_interaction_df[,"source_node"]%in%module_promoters_te_d6 & te_d6_interaction_df[,"target_node"]%in%module_promoters_te_d6,c("source_node","target_node")]
xyz=NULL
for (i in te_3d_arrow_dna_dna[,"source_node"]){
xyz=rbind(xyz,te_d6_dna_module_acp$x[rownames(te_d6_dna_module_acp$x)==i,c(1:3)])
}
xyz_end=NULL
for (i in te_3d_arrow_dna_dna[,"target_node"]){
xyz_end=rbind(xyz_end,te_d6_dna_module_acp$x[rownames(te_d6_dna_module_acp$x)==i,c(1:3)])
}
te_dna_dna_3d_arrows=data.frame(te_3d_arrow_dna_dna,x_3d_arrow=xyz[,1],y_3d_arrow=xyz[,2], z_3d_arrow=xyz[,3],xend_3d_arrow=xyz_end[,1],yend_3d_arrow=xyz_end[,2],zend_3d_arrow=xyz_end[,3])
epi_d6_module_3d_arrows=NULL
epi_3d_arrow_rna_rna=epi_d6_interaction_df[epi_d6_interaction_df[,"source_node"]%in%module_transcripts_epi_d6 & epi_d6_interaction_df[,"target_node"]%in%module_transcripts_epi_d6,c("source_node","target_node")]
xyz=NULL
for (i in epi_3d_arrow_rna_rna[,"source_node"]){
xyz=rbind(xyz,epi_d6_rna_module_acp$x[rownames(epi_d6_rna_module_acp$x)==i,c(1:3)]+5)
}
xyz_end=NULL
for (i in epi_3d_arrow_rna_rna[,"target_node"]){
xyz_end=rbind(xyz_end,epi_d6_rna_module_acp$x[rownames(epi_d6_rna_module_acp$x)==i,c(1:3)]+5)
}
epi_rna_rna_3d_arrows=data.frame(epi_3d_arrow_rna_rna,x_3d_arrow=xyz[,1],y_3d_arrow=xyz[,2], z_3d_arrow=xyz[,3],xend_3d_arrow=xyz_end[,1],yend_3d_arrow=xyz_end[,2],zend_3d_arrow=xyz_end[,3])
pe_d8_module_3d_arrows=NULL
pe_3d_arrow_rna_rna=pe_d8_interaction_df[pe_d8_interaction_df[,"source_node"]%in%module_transcripts_pe_d8 & pe_d8_interaction_df[,"target_node"]%in%module_transcripts_pe_d8,c("source_node","target_node")]
xyz=NULL
for (i in pe_3d_arrow_rna_rna[,"source_node"]){
xyz=rbind(xyz,pe_d8_rna_module_acp$x[rownames(pe_d8_rna_module_acp$x)==i,c(1:3)]+5)
}
xyz_end=NULL
for (i in pe_3d_arrow_rna_rna[,"target_node"]){
xyz_end=rbind(xyz_end,pe_d8_rna_module_acp$x[rownames(pe_d8_rna_module_acp$x)==i,c(1:3)]+5)
}
pe_rna_rna_3d_arrows=data.frame(pe_3d_arrow_rna_rna,x_3d_arrow=xyz[,1],y_3d_arrow=xyz[,2], z_3d_arrow=xyz[,3],xend_3d_arrow=xyz_end[,1],yend_3d_arrow=xyz_end[,2],zend_3d_arrow=xyz_end[,3])
te_d6_module_3d_arrows=NULL
te_3d_arrow_rna_rna=te_d6_interaction_df[te_d6_interaction_df[,"source_node"]%in%module_transcripts_te_d6 & te_d6_interaction_df[,"target_node"]%in%module_transcripts_te_d6,c("source_node","target_node")]
xyz=NULL
for (i in te_3d_arrow_rna_rna[,"source_node"]){
xyz=rbind(xyz,te_d6_rna_module_acp$x[rownames(te_d6_rna_module_acp$x)==i,c(1:3)]+5)
}
xyz_end=NULL
for (i in te_3d_arrow_rna_rna[,"target_node"]){
xyz_end=rbind(xyz_end,te_d6_rna_module_acp$x[rownames(te_d6_rna_module_acp$x)==i,c(1:3)]+5)
}
te_rna_rna_3d_arrows=data.frame(te_3d_arrow_rna_rna,x_3d_arrow=xyz[,1],y_3d_arrow=xyz[,2], z_3d_arrow=xyz[,3],xend_3d_arrow=xyz_end[,1],yend_3d_arrow=xyz_end[,2],zend_3d_arrow=xyz_end[,3])
epi_d6_module_3d_arrows=NULL
epi_3d_arrow_dna_rna=epi_d6_interaction_df[epi_d6_interaction_df[,"source_node"]%in%module_promoters_epi_d6 & epi_d6_interaction_df[,"target_node"]%in%module_transcripts_epi_d6,c("source_node","target_node")]
xyz=NULL
for (i in epi_3d_arrow_dna_rna[,"source_node"]){
xyz=rbind(xyz,epi_d6_dna_module_acp$x[rownames(epi_d6_dna_module_acp$x)==i,c(1:3)])
}
xyz_end=NULL
for (i in epi_3d_arrow_dna_rna[,"target_node"]){
xyz_end=rbind(xyz_end,epi_d6_rna_module_acp$x[rownames(epi_d6_rna_module_acp$x)==i,c(1:3)]+5)
}
epi_dna_rna_3d_arrows=data.frame(epi_3d_arrow_dna_rna,x_3d_arrow=xyz[,1],y_3d_arrow=xyz[,2], z_3d_arrow=xyz[,3],xend_3d_arrow=xyz_end[,1],yend_3d_arrow=xyz_end[,2],zend_3d_arrow=xyz_end[,3])
pe_d8_module_3d_arrows=NULL
pe_3d_arrow_dna_rna=pe_d8_interaction_df[pe_d8_interaction_df[,"source_node"]%in%module_promoters_pe_d8 & pe_d8_interaction_df[,"target_node"]%in%module_transcripts_pe_d8,c("source_node","target_node")]
xyz=NULL
for (i in pe_3d_arrow_dna_rna[,"source_node"]){
xyz=rbind(xyz,pe_d8_dna_module_acp$x[rownames(pe_d8_dna_module_acp$x)==i,c(1:3)])
}
xyz_end=NULL
for (i in pe_3d_arrow_dna_rna[,"target_node"]){
xyz_end=rbind(xyz_end,pe_d8_rna_module_acp$x[rownames(pe_d8_rna_module_acp$x)==i,c(1:3)]+5)
}
pe_dna_rna_3d_arrows=data.frame(pe_3d_arrow_dna_rna,x_3d_arrow=xyz[,1],y_3d_arrow=xyz[,2], z_3d_arrow=xyz[,3],xend_3d_arrow=xyz_end[,1],yend_3d_arrow=xyz_end[,2],zend_3d_arrow=xyz_end[,3])
te_d6_module_3d_arrows=NULL
te_3d_arrow_dna_rna=te_d6_interaction_df[te_d6_interaction_df[,"source_node"]%in%module_promoters_te_d6 & te_d6_interaction_df[,"target_node"]%in%module_transcripts_te_d6,c("source_node","target_node")]
xyz=NULL
for (i in te_3d_arrow_dna_rna[,"source_node"]){
xyz=rbind(xyz,te_d6_dna_module_acp$x[rownames(te_d6_dna_module_acp$x)==i,c(1:3)])
}
xyz_end=NULL
for (i in te_3d_arrow_dna_rna[,"target_node"]){
xyz_end=rbind(xyz_end,te_d6_rna_module_acp$x[rownames(te_d6_rna_module_acp$x)==i,c(1:3)]+5)
}
te_dna_rna_3d_arrows=data.frame(te_3d_arrow_dna_rna,x_3d_arrow=xyz[,1],y_3d_arrow=xyz[,2], z_3d_arrow=xyz[,3],xend_3d_arrow=xyz_end[,1],yend_3d_arrow=xyz_end[,2],zend_3d_arrow=xyz_end[,3])
epi_d6_module_3d_arrows=NULL
epi_3d_arrow_rna_dna=epi_d6_interaction_df[epi_d6_interaction_df[,"source_node"]%in%module_transcripts_epi_d6 & epi_d6_interaction_df[,"target_node"]%in%module_promoters_epi_d6,c("source_node","target_node")]
xyz=NULL
for (i in epi_3d_arrow_rna_dna[,"source_node"]){
xyz=rbind(xyz,epi_d6_rna_module_acp$x[rownames(epi_d6_rna_module_acp$x)==i,c(1:3)]+5)
}
xyz_end=NULL
for (i in epi_3d_arrow_rna_dna[,"target_node"]){
xyz_end=rbind(xyz_end,epi_d6_dna_module_acp$x[rownames(epi_d6_dna_module_acp$x)==i,c(1:3)])
}
epi_rna_dna_3d_arrows=data.frame(epi_3d_arrow_rna_dna,x_3d_arrow=xyz[,1],y_3d_arrow=xyz[,2], z_3d_arrow=xyz[,3],xend_3d_arrow=xyz_end[,1],yend_3d_arrow=xyz_end[,2],zend_3d_arrow=xyz_end[,3])
pe_d8_module_3d_arrows=NULL
pe_3d_arrow_rna_dna=pe_d8_interaction_df[pe_d8_interaction_df[,"source_node"]%in%module_transcripts_pe_d8 & pe_d8_interaction_df[,"target_node"]%in%module_promoters_pe_d8,c("source_node","target_node")]
xyz=NULL
for (i in pe_3d_arrow_rna_dna[,"source_node"]){
xyz=rbind(xyz,pe_d8_rna_module_acp$x[rownames(pe_d8_rna_module_acp$x)==i,c(1:3)]+5)
}
xyz_end=NULL
for (i in pe_3d_arrow_rna_dna[,"target_node"]){
xyz_end=rbind(xyz_end,pe_d8_dna_module_acp$x[rownames(pe_d8_dna_module_acp$x)==i,c(1:3)])
}
pe_rna_dna_3d_arrows=data.frame(pe_3d_arrow_rna_dna,x_3d_arrow=xyz[,1],y_3d_arrow=xyz[,2], z_3d_arrow=xyz[,3],xend_3d_arrow=xyz_end[,1],yend_3d_arrow=xyz_end[,2],zend_3d_arrow=xyz_end[,3])
te_d6_module_3d_arrows=NULL
te_3d_arrow_rna_dna=te_d6_interaction_df[te_d6_interaction_df[,"source_node"]%in%module_transcripts_te_d6 & te_d6_interaction_df[,"target_node"]%in%module_promoters_te_d6,c("source_node","target_node")]
xyz=NULL
for (i in te_3d_arrow_rna_dna[,"source_node"]){
xyz=rbind(xyz,te_d6_rna_module_acp$x[rownames(te_d6_rna_module_acp$x)==i,c(1:3)]+5)
}
xyz_end=NULL
for (i in te_3d_arrow_rna_dna[,"target_node"]){
xyz_end=rbind(xyz_end,te_d6_dna_module_acp$x[rownames(te_d6_dna_module_acp$x)==i,c(1:3)])
}
te_rna_dna_3d_arrows=data.frame(te_3d_arrow_rna_dna,x_3d_arrow=xyz[,1],y_3d_arrow=xyz[,2], z_3d_arrow=xyz[,3],xend_3d_arrow=xyz_end[,1],yend_3d_arrow=xyz_end[,2],zend_3d_arrow=xyz_end[,3])
epi_d6_3d_arrows=rbind(epi_dna_dna_3d_arrows, epi_dna_rna_3d_arrows, epi_rna_rna_3d_arrows, epi_rna_dna_3d_arrows)
pe_d8_3d_arrows=rbind(pe_dna_dna_3d_arrows, pe_dna_rna_3d_arrows, pe_rna_rna_3d_arrows, pe_rna_dna_3d_arrows)
te_d6_3d_arrows=rbind(te_dna_dna_3d_arrows, te_dna_rna_3d_arrows, te_rna_rna_3d_arrows, te_rna_dna_3d_arrows)
epi_d6_module_acp=rbind(epi_d6_dna_module_acp$x[,c(1:3)], epi_d6_rna_module_acp$x[,c(1:3)]+5)
epi_d6_size=c(epi_d6_dna_size,epi_d6_rna_size)
scene = list(
xaxis = list(
title = "",
zeroline = FALSE,
showline = FALSE,
showticklabels = FALSE,
showgrid = FALSE
),
yaxis = list(
title = "",
zeroline = FALSE,
showline = FALSE,
showticklabels = FALSE,
showgrid = FALSE
),
zaxis = list(
title = "",
zeroline = FALSE,
showline = FALSE,
showticklabels = FALSE,
showgrid = FALSE
))
epi_d6_module_acp_fig <- plot_ly(x=epi_d6_module_acp[,"PC1"], y=epi_d6_module_acp[,"PC2"], z=epi_d6_module_acp[,"PC3"]
,alpha=0.5,
size = ~log(epi_d6_size+1,10), marker = list(symbol = 'circle', sizemode = 'diameter'), sizes = c(13,120),color=~c(rep("dna",length(module_promoters_epi_d6)),rep("rna",length(module_transcripts_epi_d6))),colors=c("green","purple")
) %>% add_markers(
text = rownames(epi_d6_module_acp),
textfont = list(size=log2(epi_d6_size+1.5)*15, color= c(rep("green",length(module_promoters_epi_d6)),rep("purple",length(module_transcripts_epi_d6)))),
showlegend = T)%>%layout(scene=scene)
epi_d6_module_arrow_fig=NULL
for (i in seq(nrow(rbind(epi_dna_dna_3d_arrows,epi_dna_rna_3d_arrows)))){
plot_ly() %>%
add_trace(x = c(epi_d6_3d_arrows$x_3d_arrow[i],epi_d6_3d_arrows$xend_3d_arrow[i]),
y = c(epi_d6_3d_arrows$y_3d_arrow[i],epi_d6_3d_arrows$yend_3d_arrow[i]),
z = c(epi_d6_3d_arrows$z_3d_arrow[i],epi_d6_3d_arrows$zend_3d_arrow[i]),
type = "scatter3d", mode = "lines", name = "lines", showlegend = FALSE,
line=list(color="green", width = 1, alpha=0.1)) -> epi_d6_module_arrow_fig[[i]]
}
for (i in seq(nrow(rbind(epi_dna_dna_3d_arrows,epi_dna_rna_3d_arrows)),(nrow(rbind(epi_dna_dna_3d_arrows,epi_dna_rna_3d_arrows))+nrow(rbind(epi_rna_rna_3d_arrows,epi_rna_dna_3d_arrows))))){
plot_ly() %>%
add_trace(x = c(epi_d6_3d_arrows$x_3d_arrow[i],epi_d6_3d_arrows$xend_3d_arrow[i]),
y = c(epi_d6_3d_arrows$y_3d_arrow[i],epi_d6_3d_arrows$yend_3d_arrow[i]),
z = c(epi_d6_3d_arrows$z_3d_arrow[i],epi_d6_3d_arrows$zend_3d_arrow[i]),
type = "scatter3d", mode = "lines", name = "lines", showlegend = FALSE,
line=list(color="purple", width = 1, alpha=0.1))%>%layout(scene=scene) -> epi_d6_module_arrow_fig[[i]]
}
epi_d6_module_arrow_fig$nodes=epi_d6_module_acp_fig
subplot(epi_d6_module_arrow_fig)
pe_d8_module_acp=rbind(pe_d8_dna_module_acp$x[,c(1:3)], pe_d8_rna_module_acp$x[,c(1:3)]+5)
pe_d8_size=c(pe_d8_dna_size,pe_d8_rna_size)
scene = list(
xaxis = list(
title = "",
zeroline = FALSE,
showline = FALSE,
showticklabels = FALSE,
showgrid = FALSE
),
yaxis = list(
title = "",
zeroline = FALSE,
showline = FALSE,
showticklabels = FALSE,
showgrid = FALSE
),
zaxis = list(
title = "",
zeroline = FALSE,
showline = FALSE,
showticklabels = FALSE,
showgrid = FALSE
))
pe_d8_module_acp_fig <- plot_ly(x=pe_d8_module_acp[,"PC1"], y=pe_d8_module_acp[,"PC2"], z=pe_d8_module_acp[,"PC3"]
,alpha=0.5,
size = ~log(pe_d8_size+1,10), marker = list(symbol = 'circle', sizemode = 'diameter'), sizes = c(13,120),color=~c(rep("dna",length(module_promoters_pe_d8)),rep("rna",length(module_transcripts_pe_d8))),colors=c("green","purple")
) %>% add_markers(
text = rownames(pe_d8_module_acp),
textfont = list(size=log2(pe_d8_size+1.5)*15, color= c(rep("green",length(module_promoters_pe_d8)),rep("purple",length(module_transcripts_pe_d8)))),
showlegend = T)%>%layout(scene=scene)
pe_d8_module_arrow_fig=NULL
for (i in seq(nrow(rbind(pe_dna_dna_3d_arrows,pe_dna_rna_3d_arrows)))){
plot_ly() %>%
add_trace(x = c(pe_d8_3d_arrows$x_3d_arrow[i],pe_d8_3d_arrows$xend_3d_arrow[i]),
y = c(pe_d8_3d_arrows$y_3d_arrow[i],pe_d8_3d_arrows$yend_3d_arrow[i]),
z = c(pe_d8_3d_arrows$z_3d_arrow[i],pe_d8_3d_arrows$zend_3d_arrow[i]),
type = "scatter3d", mode = "lines", name = "lines", showlegend = FALSE,
line=list(color="green", width = 1, alpha=0.1)) -> pe_d8_module_arrow_fig[[i]]
}
for (i in seq(nrow(rbind(pe_dna_dna_3d_arrows,pe_dna_rna_3d_arrows)),(nrow(rbind(pe_dna_dna_3d_arrows,pe_dna_rna_3d_arrows))+nrow(rbind(pe_rna_rna_3d_arrows,pe_rna_dna_3d_arrows))))){
plot_ly() %>%
add_trace(x = c(pe_d8_3d_arrows$x_3d_arrow[i],pe_d8_3d_arrows$xend_3d_arrow[i]),
y = c(pe_d8_3d_arrows$y_3d_arrow[i],pe_d8_3d_arrows$yend_3d_arrow[i]),
z = c(pe_d8_3d_arrows$z_3d_arrow[i],pe_d8_3d_arrows$zend_3d_arrow[i]),
type = "scatter3d", mode = "lines", name = "lines", showlegend = FALSE,
line=list(color="purple", width = 1, alpha=0.1))%>%layout(scene=scene) -> pe_d8_module_arrow_fig[[i]]
}
pe_d8_module_arrow_fig$nodes=pe_d8_module_acp_fig
subplot(pe_d8_module_arrow_fig)
te_d6_module_acp=rbind(te_d6_dna_module_acp$x[,c(1:3)], te_d6_rna_module_acp$x[,c(1:3)]+5)
te_d6_size=c(te_d6_dna_size,te_d6_rna_size)
scene = list(
xaxis = list(
title = "",
zeroline = FALSE,
showline = FALSE,
showticklabels = FALSE,
showgrid = FALSE
),
yaxis = list(
title = "",
zeroline = FALSE,
showline = FALSE,
showticklabels = FALSE,
showgrid = FALSE
),
zaxis = list(
title = "",
zeroline = FALSE,
showline = FALSE,
showticklabels = FALSE,
showgrid = FALSE
))
te_d6_module_acp_fig <- plot_ly(x=te_d6_module_acp[,"PC1"], y=te_d6_module_acp[,"PC2"], z=te_d6_module_acp[,"PC3"]
,alpha=0.5,
size = ~log(te_d6_size+1,10), marker = list(symbol = 'circle', sizemode = 'diameter'), sizes = c(13,120),color=~c(rep("dna",length(module_promoters_te_d6)),rep("rna",length(module_transcripts_te_d6))),colors=c("green","purple")
) %>% add_markers(
text = rownames(te_d6_module_acp),
textfont = list(size=log2(te_d6_size+1.5)*15, color= c(rep("green",length(module_promoters_te_d6)),rep("purple",length(module_transcripts_te_d6)))),
showlegend = T)%>%layout(scene=scene)
te_d6_module_arrow_fig=NULL
for (i in seq(nrow(rbind(te_dna_dna_3d_arrows,te_dna_rna_3d_arrows)))){
plot_ly() %>%
add_trace(x = c(te_d6_3d_arrows$x_3d_arrow[i],te_d6_3d_arrows$xend_3d_arrow[i]),
y = c(te_d6_3d_arrows$y_3d_arrow[i],te_d6_3d_arrows$yend_3d_arrow[i]),
z = c(te_d6_3d_arrows$z_3d_arrow[i],te_d6_3d_arrows$zend_3d_arrow[i]),
type = "scatter3d", mode = "lines", name = "lines", showlegend = FALSE,
line=list(color="green", width = 1, alpha=0.1)) -> te_d6_module_arrow_fig[[i]]
}
for (i in seq(nrow(rbind(te_dna_dna_3d_arrows,te_dna_rna_3d_arrows)),(nrow(rbind(te_dna_dna_3d_arrows,te_dna_rna_3d_arrows))+nrow(rbind(te_rna_rna_3d_arrows,te_rna_dna_3d_arrows))))){
plot_ly() %>%
add_trace(x = c(te_d6_3d_arrows$x_3d_arrow[i],te_d6_3d_arrows$xend_3d_arrow[i]),
y = c(te_d6_3d_arrows$y_3d_arrow[i],te_d6_3d_arrows$yend_3d_arrow[i]),
z = c(te_d6_3d_arrows$z_3d_arrow[i],te_d6_3d_arrows$zend_3d_arrow[i]),
type = "scatter3d", mode = "lines", name = "lines", showlegend = FALSE,
line=list(color="purple", width = 1, alpha=0.1))%>%layout(scene=scene) -> te_d6_module_arrow_fig[[i]]
}
te_d6_module_arrow_fig$nodes=te_d6_module_acp_fig
subplot(te_d6_module_arrow_fig)
Mix-Kernel analysis
We want now to go further and use a kernel based approach, which computes a multi-dimension space in which embryo cells will place given their vicinity across gene promoter methylation and gene expression. This exploratory non-supervised analysis traces a non-linear frontier of decision that allocates individuals into groups (Mariette and Vialaneix, 2018).
[1] 130 130
[1] 130 130
cim.kernel(dna = dna_kernel,
rna = rna_kernel,
method = "square"
)
rna_dna_meta_kernel <- combine.kernels(dna = dna_kernel,
rna = rna_kernel,
method = "full-UMKL")
kernel.pca.result <- kernel.pca(rna_dna_meta_kernel, ncomp = 10)
# save.image("2021_06_09_embryo_kernel")
load("2021_06_09_embryo_kernel")
We needed a space within cells segregate by developmental stage and lineage progression -> kernel almost succeeded. Indeed, contrary to single PCA or UMAP, kernel recapitulates both developmental stage progression and lineage specification.
We can use this kernel space to visualize methylation and expression of genes, notably WGCNA module genes, throughout early development of the human embryo.
lineage_kernel=lineage[rownames(kernel.pca.result$x)]
next3d()
scene_kernel = list(camera = list(eye = list(x = 0, y = 0, z = 1.25)))
fig <- plot_ly(x=kernel.pca.result$x[,1],y=kernel.pca.result$x[,2],z=kernel.pca.result$x[,3],color = ~factor(lineage_kernel,levels=c("Epi", "PE", "TE")), colors = c("red","green","blue"),alpha=0.6)
fig <- fig %>% add_markers()
fig
day_kernel=day[rownames(kernel.pca.result$x)]
next3d()
scene_kernel = list(camera = list(eye = list(x = 0, y = 0, z = 1.25)))
fig <- plot_ly(x=kernel.pca.result$x[,1],y=kernel.pca.result$x[,2],z=kernel.pca.result$x[,3],color = ~factor(day_kernel,levels=c("D6", "D8", "D10", "D12")), colors = c("yellow","turquoise","purple","red"),alpha=0.6)
fig <- fig %>% add_markers()
fig
promoter_kernel=log2(dna_upm_subset[which(rownames(dna_upm_subset)=="POU5F1"),]+1)
next3d()
scene_kernel = list(camera = list(eye = list(x = 0, y = 0, z = 1.25)))
fig <- plot_ly(x=kernel.pca.result$x[,1],y=kernel.pca.result$x[,2],z=kernel.pca.result$x[,3],color = ~promoter_kernel,alpha=1, colors=c("blue","lightblue","#FFC0CB","red"))
fig <- fig %>% add_markers()
fig
transcript_kernel=log2(rna_subset[which(rownames(rna_subset)=="POU5F1"),]+1)
next3d()
scene_kernel = list(camera = list(eye = list(x = 0, y = 0, z = 1.25)))
fig <- plot_ly(x=kernel.pca.result$x[,1],y=kernel.pca.result$x[,2],z=kernel.pca.result$x[,3],color = ~transcript_kernel,alpha=1, colors=c("blue","lightblue","#FFC0CB","red"))
fig <- fig %>% add_markers()
fig
terf1_rna_boxplot=data.frame(metadata,expr=log2(rna_subset[which(rownames(rna_subset)=="TERF1"),]+1),lineage_day=paste0(metadata$lineage,"_",metadata$day))
terf1_rna_boxplot$lineage_day=factor(terf1_rna_boxplot$lineage_day,levels=c("Epi_D6", "Epi_D8", "Epi_D10", "PE_D6", "PE_D8", "PE_D10", "PE_D12", "TE_D6", "TE_D8", "TE_D10", "TE_D12"))
ggplot(terf1_rna_boxplot,aes(x=lineage_day,y=expr,fill=lineage_day))+
geom_boxplot()+
scale_fill_manual(values=c("#ff6eeb","#f01dbd","#f01d8d","#5df700","#20cc2d","#10ae4a","#39a455","#04f1fc","#20c1e1","blue","darkblue"))+
labs(title="TERF1 gene expression")
CHEK2_dna_boxplot=data.frame(metadata,expr=log2(dna_upm_subset[which(rownames(dna_upm_subset)=="CHEK2"),]+1),lineage_day=paste0(metadata$lineage,"_",metadata$day))
CHEK2_dna_boxplot$lineage_day=factor(CHEK2_dna_boxplot$lineage_day,levels=c("Epi_D6", "Epi_D8", "Epi_D10", "PE_D6", "PE_D8", "PE_D10", "PE_D12", "TE_D6", "TE_D8", "TE_D10", "TE_D12"))
ggplot(CHEK2_dna_boxplot,aes(x=lineage_day,y=expr,fill=lineage_day))+
geom_boxplot()+
scale_fill_manual(values=c("#ff6eeb","#f01dbd","#f01d8d","#5df700","#20cc2d","#10ae4a","#39a455","#04f1fc","#20c1e1","blue","darkblue"))+
labs(title="CHEK2 DNA methylation")
CHEK2_rna_boxplot=data.frame(metadata,expr=log2(rna_subset[which(rownames(rna_subset)=="CHEK2"),]+1),lineage_day=paste0(metadata$lineage,"_",metadata$day))
CHEK2_rna_boxplot$lineage_day=factor(CHEK2_rna_boxplot$lineage_day,levels=c("Epi_D6", "Epi_D8", "Epi_D10", "PE_D6", "PE_D8", "PE_D10", "PE_D12", "TE_D6", "TE_D8", "TE_D10", "TE_D12"))
ggplot(CHEK2_rna_boxplot,aes(x=lineage_day,y=expr,fill=lineage_day))+
geom_boxplot()+
scale_fill_manual(values=c("#ff6eeb","#f01dbd","#f01d8d","#5df700","#20cc2d","#10ae4a","#39a455","#04f1fc","#20c1e1","blue","darkblue"))+
labs(title="CHEK2 gene expression")



Clearly, the kernel PCA (KPCA) shows a space in which embryonic cell vicinity recapitulates both lineages and developmental day. This is of utmost interest as we could not combine these two traits with sufficient resolution.
Therefore, the kernel based approach integrates gene promoter methylation with gene expression and computes a space recapitulating developmental progression and lineage specification of the early human embryo.
LS0tDQp0aXRsZTogIkludGVncmF0ZWQgYW5hbHlzaXMgb2YgdGhlIGVhcmx5IGh1bWFuIGVtYnJ5b1xuZnJvbSBtdWx0aS1vbWljcyBzaW5nbC1jZWxsIGRhdGEiDQphdXRob3I6ICJHYcOrbCBDQVNURUwiDQpkYXRlOiAnYHIgU3lzLkRhdGUoKWAnDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgaGlnaGxpZ2h0OiB6ZW5idXJuDQogICAgdGhlbWU6IGNlcnVsZWFuDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIG1heC13aWR0aDogMTgwMHB4DQogICAgbWFyZ2luLWxlZnQ6IGF1dG8NCiAgICBtYXJnaW4tcmlnaHQ6IGF1dG8NCiAgICB3aWRlc2NyZWVuOiB5ZXMNCiAgaW9zbGlkZXNfcHJlc2VudGF0aW9uOg0KICAgIHNsaWRlX2xldmVsOiAyDQogICAgc2VsZl9jb250YWluZWQ6IHllcw0KICAgIGNvbG9ydGhlbWU6IGRvbHBoaW4NCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgZmlnX2hlaWdodDogNQ0KICAgIGZpZ193aWR0aDogNw0KICAgIGZvbnR0aGVtZTogc3RydWN0dXJlYm9sZA0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgICBzbWFsbGVyOiB5ZXMNCiAgICB0b2M6IHllcw0KICAgIHdpZGVzY3JlZW46IHllcw0KICBwZGZfZG9jdW1lbnQ6DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIGhpZ2hsaWdodDogemVuYnVybg0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAzDQogIGJlYW1lcl9wcmVzZW50YXRpb246DQogICAgY29sb3J0aGVtZTogZG9scGhpbg0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBmaWdfaGVpZ2h0OiA1DQogICAgZmlnX3dpZHRoOiA3DQogICAgZm9udHRoZW1lOiBzdHJ1Y3R1cmVib2xkDQogICAgaGlnaGxpZ2h0OiB0YW5nbw0KICAgIGluY3JlbWVudGFsOiBubw0KICAgIGtlZXBfdGV4OiBubw0KICAgIHNsaWRlX2xldmVsOiAyDQogICAgdGhlbWU6IE1vbnRwZWxsaWVyDQogICAgdG9jOiB5ZXMNCiAgcmV2ZWFsanM6OnJldmVhbGpzX3ByZXNlbnRhdGlvbjoNCiAgICB0aGVtZTogbmlnaHQNCiAgICB0cmFuc2l0aW9uOiBub25lDQogICAgc2VsZl9jb250YWluZWQ6IHRydWUNCiAgICBjc3M6IC4uL3NsaWRlcy5jc3MNCiAgc2xpZHlfcHJlc2VudGF0aW9uOg0KICAgIHNtYXJ0OiBubw0KICAgIHNsaWRlX2xldmVsOiAyDQogICAgc2VsZl9jb250YWluZWQ6IHllcw0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBmaWdfaGVpZ2h0OiA1DQogICAgZmlnX3dpZHRoOiA3DQogICAgaGlnaGxpZ2h0OiB0YW5nbw0KICAgIGluY3JlbWVudGFsOiBubw0KICAgIGtlZXBfbWQ6IHllcw0KICAgIHNtYWxsZXI6IHllcw0KICAgIHRoZW1lOiBjZXJ1bGVhbg0KICAgIHRvYzogeWVzDQogICAgd2lkZXNjcmVlbjogeWVzDQogIHBvd2VycG9pbnRfcHJlc2VudGF0aW9uOg0KICAgIHNsaWRlX2xldmVsOiAyDQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIGZpZ19oZWlnaHQ6IDUNCiAgICBmaWdfd2lkdGg6IDcNCiAgICB0b2M6IHllcw0KZm9udC1pbXBvcnQ6IGh0dHA6Ly9mb250cy5nb29nbGVhcGlzLmNvbS9jc3M/ZmFtaWx5PVJpc3F1ZQ0KZm9udC1mYW1pbHk6IEdhcmFtb25kDQp0cmFuc2l0aW9uOiBsaW5lYXINCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGNvbnNvbGUNCmhlYWRlci1pbmNsdWRlczoNCiAgIC0gXHVzZXBhY2thZ2V7ZmxvYXRyb3d9DQogICAtIFxmbG9hdHNldHVwW2ZpZ3VyZV17Y2FwcG9zaXRpb249dG9wfQ0KLS0tDQoNCjxzdHlsZT4NCi5tYWluLWNvbnRhaW5lciB7DQogICAgbWluLXdpZHRoOiAxODAwcHg7DQogICAgbWFyZ2luLWxlZnQ6IDBweDsNCiAgICBtYXJnaW4tcmlnaHQ6IDBweDsNCn0NCjwvc3R5bGU+DQoNCmBgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCnNldHdkKCJDOi9Vc2Vycy9FMTM3ODMzVC9EZXNrdG9wL2R1YmlpL3N0YWdlL2R1YmlpX3N0YWdlLyIpDQpzb3VyY2UoImh0dHBzOi8vZ2l0bGFiLnVuaXYtbmFudGVzLmZyL0UxMTQ0MjRaL3ZlbmVSL3Jhdy9tYXN0ZXIvbG9hZEZ1bi5SP2lubGluZT1mYWxzZSIpDQoNCiMgaW5zdGFsbC5wYWNrYWdlcygiaW50ZXJncmFwaCIsZGVwZW5kZW5jaWVzID0gVCwgZm9yY2U9VCxJTlNUQUxMX29wdHMgPSAnLS1uby1sb2NrJykgIyB0aGlzIHN5bnRheCB3b3JrcyBvbiB0aGUgUnN0dWRpbyBjbHVzdGVyDQoNCiMgQmlvY01hbmFnZXI6Omluc3RhbGwoInNuYSIsZGVwZW5kZW5jaWVzID0gVCwgZm9yY2U9VCxJTlNUQUxMX29wdHMgPSAnLS1uby1sb2NrJykgIyBpdCB3b3JrZWQgISBwdXQgbm8gZm9yIG1hbmlwdWxhdGV3aWRnZXQNCg0KIyByZW1vdGVzOjppbnN0YWxsX2dpdGh1YigiZGdyYXBvdi9uZXR3b3JrbHkiKQ0KDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShyZ2wpDQpsaWJyYXJ5KGRhdGEudGFibGUpDQpsaWJyYXJ5KG1hdHJpeFN0YXRzKQ0KbGlicmFyeSh1d290KQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShzdHJpbmdyKQ0KbGlicmFyeShTNFZlY3RvcnMpDQpsaWJyYXJ5KERFU2VxMikNCmxpYnJhcnkoTU9GQSkNCmxpYnJhcnkoTU9GQWRhdGEpDQpsaWJyYXJ5KEJpb2Jhc2UpDQpsaWJyYXJ5KEJpb2NHZW5lcmljcykNCmxpYnJhcnkoYmlvbWFSdCkNCmxpYnJhcnkoZm9yZWFjaCkNCmxpYnJhcnkoZG9QYXJhbGxlbCkNCmxpYnJhcnkoRmFjdG9NaW5lUikNCmxpYnJhcnkoV0dDTkEpDQpsaWJyYXJ5KHJnbCkNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZWRnZVIpDQpsaWJyYXJ5KGZhY3RvZXh0cmEpDQpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQ0KbGlicmFyeShkZW5kZXh0ZW5kKQ0KbGlicmFyeShtaXhLZXJuZWwpDQpsaWJyYXJ5KGdwcm9maWxlcjIpDQpsaWJyYXJ5KGludGVyZ3JhcGgpDQpsaWJyYXJ5KGlncmFwaCkNCmxpYnJhcnkoc25hKQ0KbGlicmFyeShnZ25ldHdvcmspDQpsaWJyYXJ5KG5ldHdvcmtseSkNCmxpYnJhcnkoc2NhbGVzKQ0KDQoNCmZhc3RSZWFkMiA8LSBmdW5jdGlvbihmaWxlTmFtZSwgc2VwID0gJ1x0Jyxyb3cubmFtZXMgPSAxLHJtLmNvbHVtbnM9MCxhcy5tYXRyaXg9RkFMU0Usc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSwuLi4pew0KICByZXF1aXJlKGRhdGEudGFibGUpDQogIGRhdCA8LSBhcy5kYXRhLmZyYW1lKGRhdGEudGFibGU6OmZyZWFkKGZpbGVOYW1lLHN0cmluZ3NBc0ZhY3RvcnM9c3RyaW5nc0FzRmFjdG9ycywgc2VwID0gc2VwLC4uLikpDQogIGlmKCFpcy5udWxsKHJvdy5uYW1lcykpew0KICAgIHJvd25hbWVzKGRhdCkgPC0gbWFrZS5uYW1lcyhkYXRbLHJvdy5uYW1lc10sIHVuaXF1ZSA9IFRSVUUpDQogICAgZGF0IDwtIGRhdFssYygtcm93Lm5hbWVzLC1ybS5jb2x1bW5zKSxkcm9wPUZBTFNFXQ0KICB9DQogIGlmKGFzLm1hdHJpeCkgZGF0PC1hcy5tYXRyaXgoZGF0KQ0KICByZXR1cm4oZGF0KQ0KfQ0KDQp0aW1lTm93PC1mdW5jdGlvbih4PU5VTEwsIHk9TlVMTCwgbT1OVUxMLCBkPU5VTEwgLCBoPU5VTEwsIG1pbj1OVUxMLHltZF9oX209TlVMTCl7eD1kYXRlKCk7DQp5PXN0cl9zdWIoeCwtNCwtMSkNCmlmKHN0cl9zdWIoeCwtMjAsLTE4KT09IkphbiIpe209IjAxIn0NCmlmKHN0cl9zdWIoeCwtMjAsLTE4KT09IkZlYiIpe209IjAyIn0NCmlmKHN0cl9zdWIoeCwtMjAsLTE4KT09Ik1hciIpe209IjAzIn0NCmlmKHN0cl9zdWIoeCwtMjAsLTE4KT09IkFwciIpe209IjA0In0NCmlmKHN0cl9zdWIoeCwtMjAsLTE4KT09Ik1heSIpe209IjA1In0NCmlmKHN0cl9zdWIoeCwtMjAsLTE4KT09Ikp1biIpe209IjA2In0NCmlmKHN0cl9zdWIoeCwtMjAsLTE4KT09Ikp1bCIpe209IjA3In0NCmlmKHN0cl9zdWIoeCwtMjAsLTE4KT09IkF1ZyIpe209IjA4In0gICAgICAgICAgICANCmlmKHN0cl9zdWIoeCwtMjAsLTE4KT09IlNlcCIpe209IjA5In0NCmlmKHN0cl9zdWIoeCwtMjAsLTE4KT09Ik9jdCIpe209IjEwIn0NCmlmKHN0cl9zdWIoeCwtMjAsLTE4KT09Ik5vdiIpe209IjExIn0NCmlmKHN0cl9zdWIoeCwtMjAsLTE4KT09IkRlYyIpe209IjEyIn0NCmQ9aWZlbHNlKHN0cl9zdWIoeCwtMTYsLTE2KSA9PSIgIixwYXN0ZTAoIjAiLHN0cl9zdWIoeCwtMTUsLTE1KSksc3RyX3N1Yih4LC0xNiwtMTUpKQ0KaD1zdHJfc3ViKHgsLTEzLC0xMikNCm1pbj1zdHJfc3ViKHgsLTEwLC05KQ0KDQpyZXR1cm4oeW1kX2hfbWluPXBhc3RlKHNlcD0iIix5LCJfIixtLCJfIixkLCJfIixoLCJfIixtaW4pKQ0KfQ0KDQprbml0cjo6b3B0c19jaHVuayRzZXQoDQogIGVjaG8gPSBUUlVFLCANCiAgZXZhbCA9IFRSVUUsIA0KICB3YXJuaW5nID0gRkFMU0UsIA0KICBtZXNzYWdlID0gRkFMU0UsIA0KICByZXN1bHRzID0gVFJVRSwgDQogIGNvbW1lbnQgPSAiIikNCg0Kb3B0aW9ucyhyZ2wudXNlTlVMTD1UUlVFKQ0KDQprbml0cjo6a25pdF9ob29rcyRzZXQod2ViZ2wgPSBob29rX3dlYmdsKQ0KDQpgYGBgDQoNCiMgSW50cm9kdWN0aW9uDQoNCkluIE1hbW1hbHMsIGxpZmUgc3RhcnRzIHdoZW4gYSBtYWxlIHNwZXJtIGNlbGwgZmVydGlsaXplcyBhIGZlbWFsZSBvb2N5dGUgdG8gZm9ybSBhIHp5Z290ZS4gVGhpcyB1bmlxdWUgdG90aXBvdGVudCBjZWxsIGNhbiBnaXZlIHJpc2UgdG8gYSBjb21wbGV0ZSBtdWx0aWNlbGx1bGFyIG9yZ2FuaXNtLiBUaGlzIGZvcm1hdGlvbiByZWxpZXMgb24gYSBzZXJpZXMgb2YgY2VsbHVsYXIgZGlmZmVyZW50aWF0aW9uIGFuZCBzcGF0aWFsIG9yZ2FuaXphdGlvbiBldmVudHMuIE11Y2ggaW5zaWdodCBpbnRvIE1hbW1hbGlhbiBkZXZlbG9wbWVudCBoYXMgY29tZSBmcm9tIHRoZSBtb3VzZSwgd2hpY2ggYmVuZWZpdHMgZnJvbSBhIHJhcGlkIGRldmVsb3BtZW50ICgyMSBkYXlzKSBhbmQgcHJvdmlkZXMgdW5yaXZhbGxlZCBhY2Nlc3NpYmlsaXR5IHRvIGVtYnJ5b3MuIFJlZ2FyZGluZyBodW1hbiBkZXZlbG9wbWVudCBob3dldmVyLCBkaWZmZXJlbmNlcyBoYXZlIGVtZXJnZWQsIGFuZCBtYW55IHF1ZXN0aW9ucyByZW1haW4gdW5zb2x2ZWQgKFtNb2xlICpldCBhbCosIDIwMjBdKCNtb2xlXzIwMjApKS4gVGhhbmtzIHRvIHRoZSBhZHZlbnQgb2Ygc2luZ2xlLWNlbGwgbXVsdGktb21pY3MgdGVjaG5pcXVlcywgd2UgaGF2ZSBub3cgYWNjZXNzIHRvIHRoZSB2ZXJ5IGludGltYXRlIG1vbGVjdWxhciBwcm9jZXNzZXMgb2NjdXJpbmcgaW4gdGhlIGVhcmx5IGh1bWFuIGVtYnJ5by4gSG93ZXZlciwgZXhwbG9yYXRpb24gb2YgdGhlc2UgZGF0YSBoYXMgYmVlbiBvcHRpbWl6ZWQsIGFuZCBub3RhYmx5LCBhIGNhcmVmdWwgaW50ZWdyYXRlZCBhbmFseXNpcyBvZiB0aGUgZGlmZmVyZW50IG9taWNzIGxldmVscyBoYXMgbm90IGJlZW4gY29uZHVjdGVkIHNvIGZhci4NCg0KSW4gdGhpcyBzdHVkeSwgd2UgcHJvcG9zZSB0byBhcHBseSBpbnRlZ3JhdGVkIGJpb2luZm9ybWF0aWNzIGFuYWx5c2VzIHRvIHRyYW5zY3JpcHRvbWljIGFuZCBtZXRoeWxvbWljIGRhdGEgb2YgdGhlIHBlcmktaW1wbGFudGF0aW9uIGh1bWFuIGVtYnJ5bywgaW4gb3JkZXIgdG8gZ2FpbiBpbnNpZ2h0IGludG8gdGhlIGludGVyY29ubmVjdGlvbiBvZiB0aGVzZSBkaWZmZXJlbnQgbW9sZWN1bGFyIGxldmVscy4gRm9yIHRoaXMgcHVycG9zZSwgd2UgdXNlIHNpbmdsZS1jZWxsIFJOQS1TZXEgYW5kIFBCQVQgZGF0YSBmcm9tIChbWmhvdSAqZXQgYWwqLCAyMDE5XSgjemhvdV8yMDE5KSksIGV4dHJhY3RlZCBmcm9tICppbiB2aXRybyogY3VsdHVyZWQgaHVtYW4gZW1icnlvcyBmcm9tIGRheSA2IHRvIDEyIG9mIGRldmVsb3BtZW50LiBUaGVzZSBkYXRhIGFyZSBwYXJ0aWN1bGFybHkgc3VpdGVkIGZvciBvdXIgYW5hbHlzaXMsIGJlY2F1c2UgdHJhbnNjcmlwdG9taWMgYW5kIEROQSBtZXRoeWxhdGlvbiBkYXRhIHdlcmUgb2J0YWluZWQgZnJvbSB0aGUgc2FtZSBjZWxsLg0KDQpGaXJzdCwgd2Ugbm9ybWFsaXplIHRoZSBkYXRhIHRvIG1ha2UgdGhlbSBzdWl0YWJsZSBmb3Igc2Vjb25kYXJ5IGFuYWx5c2lzIGFsZ29yaXRobXMuIFRoZW4sIHdlIHN0YXJ0IGludmVzdGlnYXRpbmcgZWFjaCBkYXRhc2V0IHNlcGFyYXRlbHkuIFdlIGRldGVybWluZSBpbnRlci1pbmRpdmlkdWFsIHNpbWlsYXJpdGllcyBieSBkaW1lbnNpb24gcmVkdWN0aW9uIGFwcHJvYWNoZXMgc3VjaCBhcyBQcmluY2lwYWwgQ29tcG9uZW50IEFuYWx5c2lzIChQQ0EpLiBXZSBjcm9zcy12YWxpZGF0ZSB0aGUgcmVzdWx0cyB3aXRoIHVuc3VwZXJ2aXNlZCBoaWVyYXJjaGljYWwgY2x1c3RlcmluZy4NCg0KTmV4dCwgd2UgcGVyZm9ybSBpbnRlZ3JhdGVkIGFuYWx5c2lzIG9mIHRoZSB0d28gZGF0YXNldHMgd2l0aCBkaWZmZXJlbnQgYXBwcm9hY2hlczoNCg0KLSBNdWx0aS1PbWljcyBGYWN0b3IgQW5hbHlzaXMgKE1PRkEpDQotIEtlcm5lbCBjb21wdXRhdGlvbg0KDQpXZSBmb2xsb3cgdGhlIGFuYWx5c2lzIGJ5IGludmVzdGlnYXRpbmcgc2ltaWxhcml0aWVzIGJldHdlZW4gZ2VuZSBleHByZXNzaW9uIGFuZCBETkEgbWV0aHlsYXRpb24gcGF0dGVybnMgdGhyb3VnaCB0aGUgc2FtcGxlIHRoaXMgdGltZS4gRm9yIHRoaXMgcHVycG9zZSwgd2UgdXNlIFdlaWdodGVkIEdlbmUgQ29ycmVsYXRpb24gTmV0d29yayBBbmFseXNpcyAoV0dDTkEpIGluIG9yZGVyIHRvIGlkZW50aWZ5IGNvcnJlbGF0ZWQgZ2VuZSBtb2R1bGVzLg0KDQpGaW5hbGx5LCB3ZSBjb25zdWx0IHNlbGVjdGVkIGRhdGFiYXNlcyBmb3IgZnVuY3Rpb25hbCBlbnJpY2htZW50IGFuYWx5c2lzLCBhbmQgZHJhdyBjb25jbHVzaW9ucyBhbmQgcGVyc3BlY3RpdmVzDQoNCiMgRGF0YSBwcmVwcm9jZXNzaW5nDQoNCiMjIERhdGEgZXhwbG9yYXRpb24NCg0KVGhlc2UgdHdvIGRhdGFzZXRzIGNvbnNpc3Qgb2YgMTMwIGNlbGxzIGZyb20gdGhlIHRocmVlIGVhcmxpZXN0IGNlbGwgbGluZWFnZXM6DQoNCi0gdGhlIGVwaWJsYXN0IChFUEkpLCB3aGljaCBpcyBwbHVyaXBvdGVudCBhbmQgZ2l2ZSByaXNlIHRvIHRoZSBmZXR1cw0KLSB0aGUgcHJpbWl0aXZlIGVuZG9kZXJtIChQRSksIHdoaWNoIHByb2R1Y2VzIHRoZSB5b2xrIHNhYw0KLSB0aGUgdHJvcGhlY3RvZGVybSAoVEUpLCB3aGljaCB5aWVsZHMgdGhlIHBsYWNlbnRhLg0KDQpUaGUgdGFibGUgYmVsb3cgc3VtbWFyaXplcyB0aGUgZGlzdHJpYnV0aW9uIG9mIGNlbGxzIGludG8gbGluZWFnZXMgYW5kIGVtYnJ5b25pYyBkYXlzLg0KDQpgYGBge3IgZGF0YSBsb2FkaW5nfQ0KZG5hPWFzLm1hdHJpeChmYXN0UmVhZDIoImVtYnJ5b19kbmFfbWV0aHlsYXRpb25fZ29vZC50c3YiKSkNCmNvbG5hbWVzKGRuYSk9c3ViKCJeW01ldGhfVHJpX2h2X10rKCopIiwgIlxcMSIsIGNvbG5hbWVzKGRuYSkpDQpkbmFbaXMubmEoZG5hKV0gPC0gMA0KDQpybmE9YXMubWF0cml4KGZhc3RSZWFkMigiR1NFMTA5NTU1X1RyaW9TZXFfVFBNLnR4dCIpKQ0KY29sbmFtZXMocm5hKT1zdWIoIl5bVHJpX2h2X10rKCopIiwgIlxcMSIsIGNvbG5hbWVzKHJuYSkpDQpybmE9cm5hWyxjb2xuYW1lcyhkbmEpXQ0KDQptZXRhZGF0YT1mYXN0UmVhZDIoImVtYnJ5b19tZXRhZGF0YS50c3YiKVssYygiTGluZWFnZSIsIkRheSIsIlNleCIsIkRheV9FbWIiKV0NCnJvd25hbWVzKG1ldGFkYXRhKT1zdWIoIl5bTWV0aF9UcmlfaHZfXSsoKikiLCAiXFwxIiwgcm93bmFtZXMobWV0YWRhdGEpKQ0KY29sbmFtZXMobWV0YWRhdGEpPWMoImxpbmVhZ2UiLCJkYXkiLCJzZXgiLCJlbWJyeW8iKQ0KbWV0YWRhdGE9bWV0YWRhdGFbY29sbmFtZXMoZG5hKSxdDQoNCnJvd19saW5lYWdlPU5VTEwNCg0KZm9yIChsaW5lYWdlX2kgaW4gbGV2ZWxzKGZhY3RvcihtZXRhZGF0YSRsaW5lYWdlKSkpew0KICANCiAgbGluZWFnZV9kYXk9TlVMTA0KICANCiAgZm9yIChkYXlfaSBpbiBsZXZlbHMoZmFjdG9yKG1ldGFkYXRhJGRheSxsZXZlbHMgPSBjKCJENiIsIkQ4IiwiRDEwIiwiRDEyIikpKSl7DQogICAgbGluZWFnZV9kYXk9Y2JpbmQobGluZWFnZV9kYXksbnJvdyhtZXRhZGF0YVt3aGljaChtZXRhZGF0YSRsaW5lYWdlPT1saW5lYWdlX2kgJiBtZXRhZGF0YSRkYXk9PWRheV9pKSxdKSkNCiAgfQ0KICANCiAgcm93X2xpbmVhZ2U9cmJpbmQocm93X2xpbmVhZ2UsIGxpbmVhZ2VfZGF5KQ0KfQ0KDQpyb3duYW1lcyhyb3dfbGluZWFnZSk9bGV2ZWxzKGZhY3RvcihtZXRhZGF0YSRsaW5lYWdlKSkNCmNvbG5hbWVzKHJvd19saW5lYWdlKT1sZXZlbHMoZmFjdG9yKG1ldGFkYXRhJGRheSxsZXZlbHMgPSBjKCJENiIsIkQ4IiwiRDEwIiwiRDEyIikpKQ0Kcm93X2xpbmVhZ2U9Y2JpbmQocm93X2xpbmVhZ2UsVG90YWw9cm93U3Vtcyhyb3dfbGluZWFnZSkpDQprYWJsZShyb3dfbGluZWFnZSwgY2FwdGlvbiA9ICJUYWJsZSBvZiBlbWJyeW8gY2VsbCBmZWF0dXJlcyIpDQpgYGBgDQoNCmBgYGB7ciBhbm5vdGF0aW9uIG9iamVjdHN9DQpkYXk9bWV0YWRhdGFbY29sbmFtZXMoZG5hKSwiZGF5Il0NCm5hbWVzKGRheSk9Y29sbmFtZXMoZG5hKQ0KZGF5X2NvbG9ycz1jKCJEMTAiPSJibHVlIiwiRDEyIj0icmVkIiwiRDYiPSJvcmFuZ2UiLCJEOCI9InB1cnBsZSIpDQpkYXlfY29sb3JzIDwtIGRheV9jb2xvcnNbYXMuZmFjdG9yKGRheSldDQpkYXlfc2hhcGUgPSBjKCJEMTAiPSJzcXVhcmUiLCJEMTIiPSJjaXJjbGUiLCJENiI9ICJkaWFtb25kIiwiRDgiPSAieCIpIA0KZGF5X3NoYXBlIDwtIGRheV9zaGFwZVthcy5mYWN0b3IoZGF5KV0NCmRheV9jb2xvcl9wY2FfdW1hcD11bmlxdWUoZGF5X2NvbG9ycykNCm5hbWVzKGRheV9jb2xvcl9wY2FfdW1hcCk9dW5pcXVlKG5hbWVzKGRheV9jb2xvcnMpKQ0KZGF5X3NoYXBlX3BjYV91bWFwPXVuaXF1ZShkYXlfc2hhcGUpDQpuYW1lcyhkYXlfc2hhcGVfcGNhX3VtYXApPXVuaXF1ZShuYW1lcyhkYXlfc2hhcGUpKQ0KZGF5X3RyYWl0cz1tb2RlbC5tYXRyaXgofiAwICsgZGF5LCBkYXRhPWFzLmRhdGEuZnJhbWUoZGF5KSkNCg0KbGluZWFnZT1tZXRhZGF0YVtjb2xuYW1lcyhkbmEpLCJsaW5lYWdlIl0NCm5hbWVzKGxpbmVhZ2UpPWNvbG5hbWVzKGRuYSkNCmxpbmVhZ2VfY29sb3JzPWMoIkVwaSI9InJlZCIsIlBFIj0iZ3JlZW4iLCJURSI9ImJsdWUiKQ0KbGluZWFnZV9jb2xvcnMgPC0gbGluZWFnZV9jb2xvcnNbYXMuZmFjdG9yKGxpbmVhZ2UpXQ0KbGluZWFnZV9zaGFwZSA9IGMoIkVwaSI9InNxdWFyZSIsIlBFIj0iY2lyY2xlIiwiVEUiPSAiZGlhbW9uZCIpIA0KbGluZWFnZV9zaGFwZSA8LSBsaW5lYWdlX3NoYXBlW2FzLmZhY3RvcihsaW5lYWdlKV0NCmxpbmVhZ2VfY29sb3JfcGNhX3VtYXA9dW5pcXVlKGxpbmVhZ2VfY29sb3JzKQ0KbmFtZXMobGluZWFnZV9jb2xvcl9wY2FfdW1hcCk9dW5pcXVlKG5hbWVzKGxpbmVhZ2VfY29sb3JzKSkNCmxpbmVhZ2Vfc2hhcGVfcGNhX3VtYXA9dW5pcXVlKGxpbmVhZ2Vfc2hhcGUpDQpuYW1lcyhsaW5lYWdlX3NoYXBlX3BjYV91bWFwKT11bmlxdWUobmFtZXMobGluZWFnZV9zaGFwZSkpDQpsaW5lYWdlX3RyYWl0cz1tb2RlbC5tYXRyaXgofiAwICsgbGluZWFnZSwgZGF0YT1hcy5kYXRhLmZyYW1lKGxpbmVhZ2UpKQ0KDQp0cmFpdHM9Y2JpbmQoZGF5X3RyYWl0cyxsaW5lYWdlX3RyYWl0cykNCnRyYWl0c19tYWluPWNiaW5kKGFzLm51bWVyaWMoZmFjdG9yKG1ldGFkYXRhJGxpbmVhZ2UpKSxhcy5udW1lcmljKGZhY3RvcihtZXRhZGF0YSRkYXkpKSxhcy5udW1lcmljKGZhY3RvcihtZXRhZGF0YSRzZXgpKSxhcy5udW1lcmljKGZhY3RvcihtZXRhZGF0YSRlbWJyeW8pKSkNCmNvbG5hbWVzKHRyYWl0c19tYWluKT1jb2xuYW1lcyhtZXRhZGF0YSkNCnJvd25hbWVzKHRyYWl0c19tYWluKT1yb3duYW1lcyhtZXRhZGF0YSkNCmBgYGANCg0KIyMgTm9ybWFsaXNhdGlvbiBvZiBkYXRhIGRpc3RyaWJ1dGlvbg0KDQpJbnB1dCBkYXRhIGhhdmUgYmVlbiBwcmUtcHJvY2Vzc2VkIHRvIHNvbWUgZXh0ZW50OiBtZXRoeWxhdGlvbiBsZXZlbHMgcmFuZ2UgZnJvbSAwIHRvIDEgd2hpbGUgUk5BLVNlcSBjb3VudHMgYXJlIGdpdmVuIGluIEZQS00uIEhvd2V2ZXIsIGRpc3RyaWJ1dGlvbiBvZiBmZWF0dXJlIHZhbHVlcyBkbyBub3QgZm9sbG93IGEgR2F1c3NpYW4gbGF3LiBXZSBuZWVkIHRvIG5vcm1hbGlzZSB0aGUgZGF0YSBwcmlvciB0byBmdXJ0aGVyIHByb2Nlc3NpbmcsIGluIG9yZGVyIHRvIGluY3JlYXNlIHRoZSByb2J1c3RuZXNzIG9mIHNlY29uZGFyeSBhbmFseXNlcy4NCg0KQnkgbG9va2luZyBhdCB0b3RhbCBtZWFzdXJlcyBwZXIgaW5kaXZpZHVhbCBmb3IgZWFjaCBkYXRhc2V0LCB3ZSBvYnNlcnZlIHRoYXQgbGlicmFyeSBzaXplcyBmb3IgRE5BIG1ldGh5YWx0aW9uIGRpZmZlciB3aXRoaW4gc2FtcGxlLCBsaWtlbHkgZHVlIHRvIHRlY2huaWNhbCBpc3N1ZXMgcmVsYXRlZCB0byBzZXF1ZW5jaW5nIGRlcHRoLiBTbyB3ZSBkZWNpZGUgdG8gc3RhbmRhcmRpemUgdGhpcyBzaXplIGJ5IHNjYWxpbmcgdW5pdHMgdG8gMWU2LiBJbiBjb250cmFzdCwgZWFjaCBsaWJyYXJ5IGZyb20gUk5BLVNlcSBkYXRhc2V0IGhhcyB0aGUgc2FtZSBzaXplIGFzIGl0IGNvcnJlc3BvbmRzIHRvIEZQS00uDQoNCmBgYGB7ciBhcHBseSB1cG0gdG8gZG5hfQ0KIyBOb3JtYWxpemUgbGlicmFyeSBzaXplDQoNCmRuYT1kbmEqMTAwICN0aGlzIG9wZXJhdGlvbiBpcyBvbmx5IGludGVuZGVkIHRvIGZhY2lsaXRhdGUgdmlzdWFsaXphdGlvbiBvZiBkYXRhIGluaXRpYWxseSByYW5naW5nIGZyb20gMCB0byAxDQpkbmE9cm91bmQoZG5hLDIpICN0aGlzIG9wZXJhdGlvbiBpcyBvbmx5IGludGVuZGVkIHRvIGZhY2lsaXRhdGUgY29tcGFyaXNvbiBvZiBkaXN0cmlidXRpb24gYmV0d2VlbiB0aGUgdHdvIGRhdGFzZXRzLCBzYW1lIHJvdW5kaW5nIA0KZG5hX3VwbT1yb3VuZChhcHBseShkbmEsMixmdW5jdGlvbih4KXt4L3N1bSh4KSoxZTZ9KSwyKQ0KDQpgYGBgDQoNCldlIGNhbiBhbHNvIGZpbHRlciBvdXQgbnVsbCBhbmQgbG93LXZhcmlhbmNlIGZlYXR1cmVzLCBhcyB0aGVzZSBtaWdodCBub3QgY29udGFpbiByZWxldmFudCBpbmZvcm1hdGlvbiBmb3IgZGlmZmVyZW50aWFsIGFuYWx5c2lzIHdlIHBsYW4gdG8gY29uZHVjdC4NCg0KV2Ugc3RhcnQgY3JlYXRpbmcgdGFibGVzIHRoYXQgc3VtbWFyaXplIHF1YW50aXRhdGl2ZSBtZWFzdXJlcyBwZXIgaW5kaXZpZHVhbCBhbmQgcGVyIGZlYXR1cmUuDQoNCmBgYGB7ciBkbmEgbWV0aHlsYXRpb24gbG9jaSBhbmQgdHJhbnNjcmlwdHMgc3RhdGlzdGljc30NCg0KZG5hX3VwbV9nZW5lX3N0YXRfcHJlbm9ybSA8LSBkYXRhLmZyYW1lKA0KbWVhbj1hcHBseShkbmFfdXBtLDEsbWVhbiksDQpzZD1hcHBseShkbmFfdXBtLDEsc2QpLA0KdmFyPWFwcGx5KGRuYV91cG0sMSxzZCleMiwNCmN2PWFwcGx5KGRuYV91cG0sMSxmdW5jdGlvbih4KXtzZCh4KS9tZWFuKHgpfSksDQppcXI9YXBwbHkoZG5hX3VwbSwxLGZ1bmN0aW9uKHgpIHF1YW50aWxlKHgsIHByb2JzPXNlcSgwLDEsMC4wNSksIG5hLnJtPVQpKVsiNzUlIixdLWFwcGx5KGRuYV91cG0sMSxmdW5jdGlvbih4KSBxdWFudGlsZSh4LCBwcm9icz1zZXEoMCwxLDAuMDUpLCBuYS5ybT1UKSlbIjI1JSIsXSwNCm1pbj1hcHBseShkbmFfdXBtLDEsbWluKSwNCm1lZGlhbj1hcHBseShkbmFfdXBtLDEsbWVkaWFuKSwNCm1heD1hcHBseShkbmFfdXBtLDEsbWF4KSwNCm51bGwgPSBhcHBseShkbmFfdXBtID09IDAsIDEsIHN1bSwgbmEucm0gPSBUUlVFKQ0KKQ0KDQpybmFfZ2VuZV9zdGF0X3ByZW5vcm0gPC0gZGF0YS5mcmFtZSgNCm1lYW49YXBwbHkocm5hLDEsbWVhbiksDQpzZD1hcHBseShybmEsMSxzZCksDQp2YXI9YXBwbHkocm5hLDEsc2QpXjIsDQpjdj1hcHBseShybmEsMSxmdW5jdGlvbih4KXtzZCh4KS9tZWFuKHgpfSksDQppcXI9YXBwbHkocm5hLDEsZnVuY3Rpb24oeCkgcXVhbnRpbGUoeCwgcHJvYnM9c2VxKDAsMSwwLjA1KSwgbmEucm09VCkpWyI3NSUiLF0tYXBwbHkocm5hLDEsZnVuY3Rpb24oeCkgcXVhbnRpbGUoeCwgcHJvYnM9c2VxKDAsMSwwLjA1KSwgbmEucm09VCkpWyIyNSUiLF0sDQptaW49YXBwbHkocm5hLDEsbWluKSwNCm1lZGlhbj1hcHBseShybmEsMSxtZWRpYW4pLA0KbWF4PWFwcGx5KHJuYSwxLG1heCksDQpudWxsID0gYXBwbHkocm5hID09IDAsIDEsIHN1bSwgbmEucm0gPSBUUlVFKQ0KKQ0KDQpgYGBgDQoNCmBgYGB7ciBmaWx0ZXJpbmcgb3V0IG51bGwgZmVhdHVyZXN9DQoNCiMjIERhdGEgZmlsdGVyaW5nOiBnZW5lcyBoYXZpbmcgYXQgbGVhc3QgOTAlIG51bGwgdmFsdWVzDQptZXRoX3Byb21fbnVsbCA8LSBkbmFfdXBtX2dlbmVfc3RhdF9wcmVub3JtJG51bGwgPj0gbmNvbChkbmFfdXBtKQ0KdHJhbnNjcmlwdF9udWxsIDwtIHJuYV9nZW5lX3N0YXRfcHJlbm9ybSRudWxsID49IG5jb2wocm5hKQ0KDQptZXRoX3Byb21fbG93X3ZhciA8LSBkbmFfdXBtX2dlbmVfc3RhdF9wcmVub3JtJHZhciA8PSBtZWRpYW4oZG5hX3VwbV9nZW5lX3N0YXRfcHJlbm9ybSR2YXIpDQp0cmFuc2NyaXB0X2xvd192YXIgPC0gcm5hX2dlbmVfc3RhdF9wcmVub3JtJHZhciA8PSBtZWRpYW4ocm5hX2dlbmVfc3RhdF9wcmVub3JtJHZhcikNCg0KbWV0aF9wcm9tX3N1YnNldCA9ICEobWV0aF9wcm9tX251bGwgfCBtZXRoX3Byb21fbG93X3ZhcikNCnRyYW5zY3JpcHRfc3Vic2V0ID0gISh0cmFuc2NyaXB0X251bGwgfCB0cmFuc2NyaXB0X2xvd192YXIpDQoNCmRuYV91cG1fc3Vic2V0ID0gZG5hX3VwbVttZXRoX3Byb21fc3Vic2V0LF0NCnJuYV9zdWJzZXQgPSBybmFbdHJhbnNjcmlwdF9zdWJzZXQsXQ0KDQpgYGBgDQoNCmBgYGB7ciBFeHBsb3Jpbmcgc2NQQkFUIGlucHV0IGRhdGEsIGZpZ3VyZXMtc2lkZSwgZmlnLnNob3c9ImhvbGQiLCBvdXQud2lkdGg9IjMzJSIsZmlnLmhvbGQ9VFJVRSxmaWcudG9wY2FwdGlvbiA9IFRSVUUgLCBmaWcuY2FwPSI8Y2VudGVyPioqTm9ybWFsaXNhdGlvbiBvZiBnZW5lIHByb21vdGVyIG1ldGh5bGF0aW9uIGxldmVsIGRpc3RyaWJ1dGlvbioqPC9jZW50ZXI+In0NCg0KaGlzdChkbmEsIGJyZWFrcz0xMDAsIG1haW4gPSAiSW5wdXQiKQ0KaGlzdChsb2cyKGRuYV91cG0pLCBicmVha3M9MTAwLCBtYWluID0gIlNpemUgc3RhbmRhcmRpc2F0aW9uICYgbG9nLXRyYW5zZm9ybWF0aW9uIikNCmhpc3QobG9nMihkbmFfdXBtX3N1YnNldCksIGJyZWFrcz0xMDAsIG1haW4gPSAiU2l6ZSBzdGFuZGFyZGlzYXRpb24sIGZpbHRyYXRpb24gJiBsb2ctdHJhbnNmb3JtYXRpb24iKQ0KDQpgYGBgDQoNCmBgYGB7ciBFeHBsb3Jpbmcgc2NSTkEtU2VxIGlucHV0IGRhdGEsIGZpZ3VyZXMtc2lkZSwgZmlnLnNob3c9ImhvbGQiLCBvdXQud2lkdGg9IjMzJSIsZmlnLmhvbGQ9VFJVRSxmaWcudG9wY2FwdGlvbiA9IFRSVUUgLCBmaWcuY2FwPSI8Y2VudGVyPioqTm9ybWFsaXNhdGlvbiBvZiBnZW5lIHByb21vdGVyIG1ldGh5bGF0aW9uIGxldmVscyoqPC9jZW50ZXI+In0NCg0KaGlzdChybmEsIGJyZWFrcz0xMDAsIG1haW4gPSAiSW5wdXQiKQ0KaGlzdChsb2cyKHJuYSksIGJyZWFrcz0xMDAsIG1haW4gPSAiTG9nLXRyYW5zZm9ybWF0aW9uIikNCmhpc3QobG9nMihybmFfc3Vic2V0KSwgYnJlYWtzPTEwMCwgbWFpbiA9ICJTaXplIHN0YW5kYXJkaXNhdGlvbiwgZmlsdHJhdGlvbiAmIGxvZy10cmFuc2Zvcm1hdGlvbiIpDQoNCmBgYGANCldoZW4gd2UgcGxvdCBpbnB1dCBkYXRhIGZvciB0aGUgdHdvIGRhdGFzZXRzLCB3ZSBvYnNlcnZlIGEgMCBpbmZsYXRpb24sIHdoaWNoIGNhbiBoYXZlIHR3byBvcmlnaW5zOg0KDQotIGJpb2xvZ2ljYWw6IDAgZXhwcmVzc2lvbiBvciBtZXRoeWxhdGlvbiwgdW5saWtlbHkNCi0gdGVjaG5pY2FsOiBubyBkZXRlY3Rpb24gb2YgZXhwcmVzc2lvbiBvciBtZXRoeWxhdGlvbiwgbGlrZWx5DQoNCk1vcmVvdmVyLCB3ZSBvYnNlcnZlIHRoYXQgZGlzdHJpYnV0aW9uIGlzIGFsc28gc2tld2VkIGJ5IGhpZ2ggdmFsdWVzLg0KDQpTbyBmb3IgYmV0dGVyIHZpc3VhbGl6YXRpb24gb2YgdGhlIGxhdGVudCBkaXN0cmlidXRpb24sIHdlIGFwcGx5IGxvZyB0cmFuc2Zvcm1hdGlvbiBvZiB0aGUgZGF0YSBpbiBvcmRlciB0byByZW1vdmUgMCBhbmQgcmVkdWNlIGR5bmFtaWMgcmFuZ2Ugb2YgdmFyaWFibGVzLg0KDQpCeSBkb2luZyB0aGlzLCB3ZSByZXZlYWwgdGhhdCBiaW9sb2dpY2FsbHkgcmVsYXRlZCBkaXN0cmlidXRpb24gb2YgZ2VuZSBleHByZXNzaW9uIGFuZCBETkEgbWV0aHlsYXRpb24gbGV2ZWxzIGF0IGdlbmUgcHJvbW90ZXJzLCBhZnRlciBmaWx0ZXJpbmcgb3V0IGxvdy12YXJpYW5jZSBmZWF0dXJlcywgYm90aCBhcHByb3hpbWF0ZSB0aGUgbm9ybWFsL0dhdXNzaWFuIGxhdy4NCg0KSXQgaXMgaW50ZXJlc3RpbmcgdG8gbWVudGlvbiB0aGF0IGxvdy12YXJpYW5jZSBsZXZlbHMgY29ycmVzcG9uZCB0byBsb3cgbWV0aHlsYXRlZCByZWdpb25zLCBhbmQgaWYgbm90IGZpbHRlcmVkIG91dCwgeWllbGQgYSBiaW1vZGFsIGRpc3RyaWJ1dGlvbi4NCg0KYGBgYHtyIGNsdXN0ZXJpbmcgb24gRE5BIG1ldGh5bGF0ZWQgZ2VuZSBwcm9tb3RlcnMsIGZpZ3VyZXMtc2lkZSwgZmlnLnNob3c9ImhvbGQiLCBvdXQud2lkdGg9IjUwJSIsZmlnLmhvbGQ9VFJVRSxmaWcudG9wY2FwdGlvbiA9IFRSVUUgLCBmaWcuY2FwPSI8Y2VudGVyPioqSGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcgb2YgZW1icnlvIGNlbGxzIG9uIGdlbmUgcHJvbW90ZXIgbWV0aHlsYXRpb24qKjwvY2VudGVyPiJ9DQoNCm1ldGhfcHJvbV9zYW1wbGVfZGlzdCA8LSBmYWN0b2V4dHJhOjpnZXRfZGlzdCh4ID10KGxvZzIoZG5hX3VwbV9zdWJzZXQrMSkpLCBtZXRob2QgPSAicGVhcnNvbiIpDQoNCm1ldGhfcHJvbV9zYW1wbGVfZGlzdCAlPiUNCiAgaGNsdXN0KG1ldGhvZD0id2FyZC5EMiIpICU+JQ0KICBjb2xvcl9icmFuY2hlcyhrPTIsY29sID0gYygiIzAwRkZGRiIsIiNGRjAwMDAiKSwgZ3JvdXBMYWJlbHMgPSBUKSAtPiBtZXRoX3Byb21fc2FtcGxlX2RlbmQNCg0KbGFiZWxzX2NvbG9ycyhtZXRoX3Byb21fc2FtcGxlX2RlbmQpIDwtIHJhaW5ib3coNClbZmFjdG9yKGRheVtvcmRlci5kZW5kcm9ncmFtKG1ldGhfcHJvbV9zYW1wbGVfZGVuZCldKV0NCg0KcGxvdChtZXRoX3Byb21fc2FtcGxlX2RlbmQpDQoNCg0KbWV0aF9wcm9tX3NhbXBsZV9kaXN0IDwtIGZhY3RvZXh0cmE6OmdldF9kaXN0KHggPXQobG9nMihkbmFfdXBtX3N1YnNldCsxKSksIG1ldGhvZCA9ICJwZWFyc29uIikNCg0KbWV0aF9wcm9tX3NhbXBsZV9kaXN0ICU+JQ0KICBoY2x1c3QobWV0aG9kPSJ3YXJkLkQyIikgJT4lDQogIGNvbG9yX2JyYW5jaGVzKGs9Mixjb2wgPSBjKCIjMDBGRkZGIiwiI0ZGMDAwMCIpLCBncm91cExhYmVscyA9IFQpIC0+IG1ldGhfcHJvbV9zYW1wbGVfZGVuZA0KDQpsYWJlbHNfY29sb3JzKG1ldGhfcHJvbV9zYW1wbGVfZGVuZCkgPC0gcmFpbmJvdygzKVtmYWN0b3IobGluZWFnZVtvcmRlci5kZW5kcm9ncmFtKG1ldGhfcHJvbV9zYW1wbGVfZGVuZCldKV0NCg0KcGxvdChtZXRoX3Byb21fc2FtcGxlX2RlbmQpDQpgYGBgDQoNCmBgYGB7ciBjbHVzdGVyaW5nIG9uIFJOQSBnZW5lIGV4cHJlc3Npb24sIGZpZ3VyZXMtc2lkZSwgZmlnLnNob3c9ImhvbGQiLCBvdXQud2lkdGg9IjUwJSIsZmlnLmhvbGQ9VFJVRSxmaWcudG9wY2FwdGlvbiA9IFRSVUUgLCBmaWcuY2FwPSI8Y2VudGVyPioqSGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcgb2YgZW1icnlvIGNlbGxzIG9uIGdlbmUgZXhwcmVzc2lvbioqPC9jZW50ZXI+In0NCnRyYW5zY3JpcHRfc2FtcGxlX2Rpc3QgPC0gZmFjdG9leHRyYTo6Z2V0X2Rpc3QoeCA9dChsb2cyKHJuYV9zdWJzZXQrMSkpLCBtZXRob2QgPSAicGVhcnNvbiIpDQoNCnRyYW5zY3JpcHRfc2FtcGxlX2Rpc3QgJT4lDQogIGhjbHVzdChtZXRob2Q9IndhcmQuRDIiKSAlPiUNCiAgY29sb3JfYnJhbmNoZXMoaz0xMCxjb2wgPSBjKCJibHVlIiwiYmx1ZSIsImdyZWVuIiwiYmx1ZSIsInJlZCIsInJlZCIsInJlZCIsImdyZWVuIiwiZ3JlZW4iLCJncmVlbiIpLCBncm91cExhYmVscyA9IFQpIC0+IHRyYW5zY3JpcHRfc2FtcGxlX2RlbmQNCg0KbGFiZWxzX2NvbG9ycyh0cmFuc2NyaXB0X3NhbXBsZV9kZW5kKSA8LSByYWluYm93KDQpW2ZhY3RvcihkYXlbb3JkZXIuZGVuZHJvZ3JhbSh0cmFuc2NyaXB0X3NhbXBsZV9kZW5kKV0pXQ0KDQpwbG90KHRyYW5zY3JpcHRfc2FtcGxlX2RlbmQpDQoNCg0KdHJhbnNjcmlwdF9zYW1wbGVfZGlzdCA8LSBmYWN0b2V4dHJhOjpnZXRfZGlzdCh4ID10KGxvZzIocm5hX3N1YnNldCsxKSksIG1ldGhvZCA9ICJwZWFyc29uIikNCg0KdHJhbnNjcmlwdF9zYW1wbGVfZGlzdCAlPiUNCiAgaGNsdXN0KG1ldGhvZD0id2FyZC5EMiIpICU+JQ0KICBjb2xvcl9icmFuY2hlcyhrPTEwLGNvbCA9IGMoImJsdWUiLCJibHVlIiwiZ3JlZW4iLCJibHVlIiwicmVkIiwicmVkIiwicmVkIiwiZ3JlZW4iLCJncmVlbiIsImdyZWVuIiksIGdyb3VwTGFiZWxzID0gVCkgLT4gdHJhbnNjcmlwdF9zYW1wbGVfZGVuZA0KDQpsYWJlbHNfY29sb3JzKHRyYW5zY3JpcHRfc2FtcGxlX2RlbmQpIDwtIHJhaW5ib3coMylbZmFjdG9yKGxpbmVhZ2Vbb3JkZXIuZGVuZHJvZ3JhbSh0cmFuc2NyaXB0X3NhbXBsZV9kZW5kKV0pXQ0KDQpwbG90KHRyYW5zY3JpcHRfc2FtcGxlX2RlbmQpDQoNCmBgYGANCg0KV2UgY2hvb3NlIHRvIGNhbGN1bGF0ZSBQZWFyc29uIGNvcnJlbGF0aW9uIGRpc3RhbmNlIGJldHdlZW4gRE5BIG1ldGh5bGF0ZWQgZ2VuZSBwcm9tb3RlcnMsIGJlY2F1c2UgdGhpcyBtZXRob2QgcHJvZHVjZXMgdGhlIGJlc3QgUmFuZCBBZGp1c3RlZCBJbmRleCAoW0phc2tvd2lhayAqZXQgYWwqLCAyMDE0XSgjamFza293aWFrXzIwMTQpKS4gVGhlbiB3ZSBhcHBseSBoaWVyYXJjaGljYWwgY2x1c3RlcmluZyB3aXRoIFdhcmQgbWV0aG9kICgid2FyZC5EMiIpLCBhcyB0aGlzIG1vc3Qgcm9idXN0bHkgaWRlbnRpZmllcyBncm91cHMgb2YgaW5kaXZpZHVhbHMgd2l0aCBzaW1pbGFyIHF1YW50aXRhdGl2ZSB0cmFpdHMuIEluZGVlZCwgdGhpcyBncm91cHMgaW5kaXZpZHVhbHMgYWNjb3JkaW5nIHRvIHZhcmlhbmNlIGluc3RlYWQgb2YgbWVhbiwgY29udHJhcnkgdG8gb3RoZXIgbWV0aG9kcyBzdWNoIGFzICJhdmVyYWdlIiAoW0xhd2xvciAqZXQgYWwqLCAyMDE2XSgjbGF3bG9yXzIwMTYpKS4NCg0KRm9yIG1ldGh5bGF0aW9uIGxldmVscyBvZiBnZW5lIHByb21vdGVycywgd2Ugb2JzZXJ2ZSB0aGF0IHRoZSB0d28gbWFpbiBjbHVzdGVycyBzZWdyZWdhdGUgZGF5IDYgZnJvbSBsYXRlciBkZXZlbG9wbWVudGFsIHN0YWdlcy4gSG93ZXZlciwgd2l0aGluIHRoZSBzZWNvbmQgbWFpbiBjbHVzdGVyLCB3ZSBzZWUgdGhhdCBzdWJjbHVzdGVycyB3ZWxsIHNlcGFyYXRlIGNlbGwgbGluZWFnZXMuIEZvciBzdWJzZXF1ZW50IGFuYWx5c2VzLCB3ZSB3aWxsIGNvbnNpZGVyIGFuYWx5emluZyBkYXk2IGVpdGhlciB0b2dldGhlciBvciBzZXBhcmF0ZWx5IGZyb20gbGF0ZXIgc3RhZ2VzLCBkZXBlbmRpbmcgb24gdGhlIHF1ZXN0aW9uIHRvIGJlIGFkZHJlc3NlZC4NCg0KRm9yIGdlbmUgZXhwcmVzc2lvbiwgd2Ugb2JzZXJ2ZSB0aGF0IGNsdXN0ZXJzIG5pY2VseSBzZWdyZWdhdGUgY2VsbCBsaW5lYWdlcy4NCg0KIyBEaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24gYmFzZWQgYW5hbHlzaXMgb2YgaW50ZXItaW5kaXZpZHVhbCB2aWNpbml0eQ0KDQpJbiBvcmRlciB0byBpbnZlc3RpZ2F0ZSBpbmRpdmlkdWFsIHZpY2luaXR5IHdpdGhpbiBzYW1wbGUsIHdlIHBlcmZvcm0gYSBQcmluY2lwYWwgQ29tcG9uZW50IEFuYWx5c2lzIChQQ0EpLCB3aGljaCByZWR1Y2VzIGRpbWVuc2lvbnMgd2hpbGUga2VlcGluZyBtYXhpbXVtIG9mIHNhbXBsZSB2YXJpYW5jZSBzdW1tYXJpc2VkIGluICJlaWdlbnZlY3RvcnMiIChbTGV2ZXIgKmV0IGFsKiwgMjAxN10oI2xldmVyXzIwMTcpKS4NCg0KV2UgYWxzbyBwZXJmb3JtIGFub3RoZXIgZGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uIGFuYWx5c2lzLCB0aGUgVW5pZm9ybSBNYW5pZm9sZCBBcHByb3hpbWF0aW9uIGFuZCBQcm9qZWN0aW9uIChVTUFQKSwgd2hpY2ggaXMgY29tcGxlbWVudGFyeSB0byBQQ0EsIGFzIGl0IGlzIG5vbmxpbmVhciwgYW5kIG91dHBlcmZvcm1zIHQtU05FIChbS29iYWsgKmV0IGFsKiwgMjAxOV0oI2tvYmFrXzIwMTkpKS4gQSBrZXkgcGFyYW1ldGVyIGZvciB0aGUgVU1BUCBpcyB0aGUgbnVtYmVyIG9mIG5laWdoYm91cnMgZm9yIGVhY2ggaW5kaXZpZHVhbC4gSW4gb3JkZXIgdG8gZGV0ZXJtaW5lIHRoZSBtb3N0IGFwcHJvcHJpYXRlIG51bWJlciBvZiBuZWlnaGJvdXJzIGFjY29yZGluZyB0byB0aGUgbGF0ZW50IHN0cnVjdHVyZSBvZiB0aGUgZGF0YSwgd2UgdXNlIHRoZSByZXN1bHQgb2YgdGhlIGhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nIG9mIGNlbGxzLCBjdXQgYXQgdGhyZWUgY2x1c3RlcnMgcmVjYXBpdHVsYXRpbmcgZGV2ZWxvcG1lbnRhbCBkYXlzIG9yIGNlbGwgdHlwZXMgcmVsYXRpdmUgdG8gdGhlIGRhdGFzZXQsIGFuZCBhcHBseSB0aGUgbWVhbiBudW1iZXIgb2YgY2VsbHMgcGVyIGNsdXN0ZXIuDQoNCmBgYGB7ciBwY2EgYW5kIHVtYXAgb2YgZW1icnlvIGNlbGxzIGNvbXB1dGVkIG9uIGdlbmUgcHJvbW90ZXIgbWV0aHlsYXRpb24sZmlnLnRvcGNhcHRpb24gPSBUUlVFICwgZmlnLmNhcD0iPGNlbnRlcj4qKlBDQSBhbmQgVU1BUCBvZiBlbWJyeW8gY2VsbHMgY29tcHV0ZWQgb24gZ2VuZSBwcm9tb3RlciBtZXRoeWxhdGlvbioqPC9jZW50ZXI+In0NCmRuYV9wY2E8LUFDUChsb2cyKGRuYV91cG1fc3Vic2V0KzEpKQ0KDQpkbmFfdW1hcDwtbWFrZS51bWFwMihsb2cyKGRuYV91cG1fc3Vic2V0KzEpLG5fY29tcG9uZW50cyA9IDMsbl9uZWlnaGJvcnMgPSBuY29sKGRuYV91cG1fc3Vic2V0KSxtaW5fZGlzdCA9IDAuMikjZ29vZA0KDQpybmFfcGNhPC1BQ1AobG9nMihybmFfc3Vic2V0KzEpKQ0KDQpybmFfdW1hcDwtbWFrZS51bWFwMihsb2cyKHJuYV9zdWJzZXQrMSksbl9jb21wb25lbnRzID0gMyxuX25laWdoYm9ycyA9IG5jb2wocm5hX3N1YnNldCksbWluX2Rpc3QgPSAwLjIsIG1ldHJpYz0gImNvcnJlbGF0aW9uIikjZ29vZA0KDQojIHNhdmUuaW1hZ2UoIjIwMjFfMDZfMDdfZW1icnlvX3VtYXAuUkRhdGEiKQ0KbG9hZChmaWxlID0gIjIwMjFfMDZfMDdfZW1icnlvX3VtYXAuUkRhdGEiKQ0KDQpkbmFfcGNhX2ZpZyA8LSBwbG90X2x5KHg9ZG5hX3BjYSR4WywiUEMxIl0sIHk9ZG5hX3BjYSR4WywiUEMyIl0sIHo9ZG5hX3BjYSR4WywiUEMzIl0sY29sb3IgPSB+bmFtZXMoZGF5X2NvbG9ycyksIGNvbG9ycyA9IGRheV9jb2xvcl9wY2FfdW1hcCxhbHBoYT0wLjYsc2NlbmU9J3NjZW5lMScpDQpkbmFfcGNhX2ZpZyA8LSBkbmFfcGNhX2ZpZyAlPiUgYWRkX21hcmtlcnMoKQ0KDQpkbmFfdW1hcF9maWcgPC0gcGxvdF9seSh4PWRuYV91bWFwWywxXSwgeT1kbmFfdW1hcFssMl0sIHo9ZG5hX3VtYXBbLDNdLGNvbG9yID0gfm5hbWVzKGRheV9jb2xvcnMpLCBjb2xvcnMgPSBkYXlfY29sb3JfcGNhX3VtYXAsYWxwaGE9MC42LHN5bWJvbCA9IH5uYW1lcyhsaW5lYWdlX3NoYXBlKSwgc3ltYm9scz1saW5lYWdlX3NoYXBlX3BjYV91bWFwLHNjZW5lPSdzY2VuZTInKQ0KZG5hX3VtYXBfZmlnIDwtIGRuYV91bWFwX2ZpZyAlPiUgYWRkX21hcmtlcnMoKQ0KDQpkbmFfcGNhX3VtYXBfZmlnIDwtIHN1YnBsb3QoZG5hX3BjYV9maWcsIGRuYV91bWFwX2ZpZykgDQpkbmFfcGNhX3VtYXBfZmlnIDwtIGRuYV9wY2FfdW1hcF9maWcgJT4lIGxheW91dCh0aXRsZSA9ICIzRCBTdWJwbG90cyIsDQogICAgICAgICBzY2VuZTEgPSBsaXN0KGRvbWFpbj1saXN0KHg9YygwLDAuNSkseT1jKDAsMSkpLA0KICAgICAgICAgICAgICAgICAgICAgIGFzcGVjdG1vZGU9J2N1YmUnKSwNCiAgICAgICAgIHNjZW5lMiA9IGxpc3QoZG9tYWluPWxpc3QoeD1jKDAuNSwxKSx5PWMoMCwxKSksDQogICAgICAgICAgICAgICAgICAgICAgIGFzcGVjdG1vZGU9J2N1YmUnKSkNCg0KZG5hX3BjYV91bWFwX2ZpZw0KDQpgYGBgDQoNCmBgYGB7ciBwY2EgYW5kIHVtYXAgb2YgZW1icnlvIGNlbGxzIGNvbXB1dGVkIG9uIGdlbmUgZXhwcmVzc2lvbixmaWcudG9wY2FwdGlvbiA9IFRSVUUgLCBmaWcuY2FwPSI8Y2VudGVyPioqUENBIGFuZCBVTUFQIG9mIGVtYnJ5byBjZWxscyBjb21wdXRlZCBvbiBnZW5lIGV4cHJlc3Npb24qKjwvY2VudGVyPiJ9DQoNCnJuYV9wY2FfZmlnIDwtIHBsb3RfbHkoeD1ybmFfcGNhJHhbLCJQQzEiXSwgeT1ybmFfcGNhJHhbLCJQQzIiXSwgej1ybmFfcGNhJHhbLCJQQzMiXSxjb2xvciA9IH5uYW1lcyhsaW5lYWdlX2NvbG9ycyksIGNvbG9ycyA9IGxpbmVhZ2VfY29sb3JfcGNhX3VtYXAsYWxwaGE9MC42LCBzY2VuZT0nc2NlbmUxJykNCnJuYV9wY2FfZmlnIDwtIHJuYV9wY2FfZmlnICU+JSBhZGRfbWFya2VycygpDQoNCnJuYV91bWFwX2ZpZyA8LSBwbG90X2x5KHg9cm5hX3VtYXBbLDFdLCB5PXJuYV91bWFwWywyXSwgej1ybmFfdW1hcFssM10sY29sb3IgPSB+bmFtZXMobGluZWFnZV9jb2xvcnMpLCBjb2xvcnMgPSBsaW5lYWdlX2NvbG9yX3BjYV91bWFwLGFscGhhPTAuNixzeW1ib2wgPSB+bmFtZXMoZGF5X3NoYXBlKSwgc3ltYm9scz1kYXlfc2hhcGVfcGNhX3VtYXAsIHNjZW5lPSdzY2VuZTInKQ0Kcm5hX3VtYXBfZmlnIDwtIHJuYV91bWFwX2ZpZyAlPiUgYWRkX21hcmtlcnMoKQ0KDQpybmFfcGNhX3VtYXBfZmlnIDwtIHN1YnBsb3Qocm5hX3BjYV9maWcsIHJuYV91bWFwX2ZpZykgDQpybmFfcGNhX3VtYXBfZmlnIDwtIHJuYV9wY2FfdW1hcF9maWcgJT4lIGxheW91dCh0aXRsZSA9ICIzRCBTdWJwbG90cyIsDQogICAgICAgICBzY2VuZTEgPSBsaXN0KGRvbWFpbj1saXN0KHg9YygwLDAuNSkseT1jKDAsMSkpLA0KICAgICAgICAgICAgICAgICAgICAgIGFzcGVjdG1vZGU9J2N1YmUnKSwNCiAgICAgICAgIHNjZW5lMiA9IGxpc3QoZG9tYWluPWxpc3QoeD1jKDAuNSwxKSx5PWMoMCwxKSksDQogICAgICAgICAgICAgICAgICAgICAgIGFzcGVjdG1vZGU9J2N1YmUnKSkNCg0Kcm5hX3BjYV91bWFwX2ZpZw0KIyBzYXZlLmltYWdlKHBhc3RlMCh0aW1lTm93KCksImVtYnJ5b19kbmFfcm5hX3VtYXAuUkRhdGEiKSkNCmBgYGANCg0KV2Ugb2JzZXJ2ZSB0aGF0IGFwcGx5aW5nIHRoZSAiY29ycmVsYXRpb24iIG1ldHJpYyBiYXNlZCBvbiBQZWFyc29uIGRpc3RhbmNlIHRvIHVtYXAgY2FsY3VsYXRpb24gcHJvdmlkZXMgbXVjaCBiZXR0ZXIgcmVzdWx0cyB0aGFuIGV1Y2xpZGVhbiBkaXN0YW5jZS4NCg0KUENBIGFuZCBVTUFQIHlpZWxkIGdyb3VwcyBvZiBpbmRpdmlkdWFscyBpbiBsaW5lIHdpdGggaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcuIEZvciBib3RoIGFuYWx5c2VzLCB3ZSBvYnNlcnZlIHRoYXQgZ2VuZSBwcm9tb3RlciBtZXRoeWxhdGlvbiBtYWlubHkgcmVjYXBpdHVsYXRlcyBkZXZlbG9wbWVudGFsIHByb2dyZXNzaW9uIChlbWJyeW9uaWMgZGF5cykgd2hpbGUgZ2VuZSBleHByZXNzaW9uIHJlY2FwaXR1bGF0ZXMgY2VsbCBsaW5lYWdlcyhFUEksIFBFLCBURSkuIFRoaXMgb2JzZXJ2YXRpb24gaXMgaW4gbGluZSB3aXRoIHByZXZpb3VzbHkgcHVibGlzaGVkIHJlc3VsdHMgZnJvbSAoW1pob3UgKmV0IGFsKiwgMjAxOV0oI3pob3VfMjAxOSkpLCBhcyBzaG93biBpbiB0aGUgZmlndXJlIGJlbG93Og0KDQoiUHJpbmNpcGFsIGNvbXBvbmVudCBhbmFseXNpcyANCm9mIEROQSBtZXRoeWxvbWUgZGF0YSBzaG93ZWQgdGhhdCB0aGVzZSAxMzAgY2VsbHMgZm9ybWVkIDQgbWFqb3IgDQpjbHVzdGVycyAoRXh0ZW5kZWQgRGF0YSBGaWcuIDhnLCBoKSwgd2l0aCBhIGNvbWJpbmF0aW9uIG9mIHRoZSBFUEksIFBFIA0KYW5kIFRFIGF0IHRoZSBibGFzdG9jeXN0IHN0YWdlIChkYXkgNikgYXMgYSBzaW5nbGUgY2x1c3RlciwgYW5kIHRoZSBFUEksIA0KUEUgYW5kIFRFIGJleW9uZCB0aGUgYmxhc3RvY3lzdCBzdGFnZSBhcyBhbm90aGVyIDMgc2VwYXJhdGUgY2x1c3RlcnMsIA0Kc3VnZ2VzdGluZyB0aGF0IGFsbCBvZiB0aGUgMyBsaW5lYWdlcyBzaG93ZWQgY29uc2lkZXJhYmxlIGNoYW5nZXMgaW4gDQpETkEgbWV0aHlsYXRpb24gc29vbiBhZnRlciBpbXBsYW50YXRpb24uIg0KDQpJbiB0ZXJtcyBvZiBiaW9sb2d5LCB0aGlzIGNvdWxkIG1lYW4gdGhhdCBhdCBkYXkgNiwgZ2xvYmFsIEROQSBtZXRoeWxhdGlvbiBzdGF0ZSByZXN1bHRzIGZyb20gZXBpZ2VuZXRpYyB3YXZlcyBhdCBlYXJseSBlbWJyeW9uaWMgc3RhZ2VzLCBwcmlvciB0byBsaW5lYWdlIHNwZWNpZmljYXRpb24uIExhdGVyIHN0YWdlcyBzaG93IHJld3JpdGluZyBvZiBlcGlnZW5ldGljIG1hcmtzIHNwZWNpZmljIHRvIGNlbGwgbGluZWFnZXMsIHdoaWNoIGhhdmUgZGlzdGluY3QgdHJhbnNjcmlwdG9taWMgc2lnbmF0dXJlcy4NCg0KVGhpcyBvYnNlcnZhdGlvbiBpcyBpbnRlcmVzdGluZyBhcyBhIGNvbWJpbmF0aW9uIG9mIEROQSBtZXRoeWxhdGlvbiBhbmQgZ2VuZSBleHByZXNzaW9uIGxldmVscyBtaWdodCBhbGxvdyB0byBhc3NpZ24gZGV2ZWxvcG1lbnRhbCBzdGFnZSBhbmQgbGluZWFnZSB0byBzaW5nbGUgY2VsbHMgb2YgdGhlIGh1bWFuIGVtYnJ5by4NCg0KIyBXR0NOQQ0KDQpBZnRlciBjb25zaWRlcmluZyBpbnRlci1pbmRpdmlkdWFsIHZpY2luaXR5LCB3ZSBub3cgaW52ZXN0aWdhdGUgY29ycmVsYXRpb24gd2l0aGluIHNhbXBsZSBhdCBnZW5lIHByb21vdGVyIG1ldGh5bGF0aW9uIGFuZCBnZW5lIGV4cHJlc3Npb24gbGV2ZWxzLiBGb3IgdGhpcyBwdXJwb3NlLCB3ZSBwZXJmb3JtIFdlaWdodGVkIEdlbmUgTmV0d29yayBDb3JyZWxhdGlvbiBBbmFseXNpcyAoV0dDTkEpLiBUaGlzIGFsZ29yaXRobSBzZWFyY2hlcyBmb3IgYSBsYXRlbnQgc3RydWN0dXJlIHdpdGhpbiBmZWF0dXJlcywgaS5lIG1vZHVsZXMgb2YgY29ycmVsYXRlZCBnZW5lcyBhdCBwcm9tb3RlciBtZXRoeWxhdGlvbiBvciB0cmFuc2NyaXB0aW9uYWwgbGV2ZWxzIChbTGFuZ2ZlbGRlciAqZXQgYWwqLCAyMDA4XSgjbGFuZ2ZlbGRlcl8yMDA4KSkuDQoNCiMjIFBhcmFtZXRlciBzZXR0aW5ncyAmIFdHQ05BIGNvbXB1dGF0aW9uDQoNCkZpcnN0LCB3ZSBuZWVkIHRvIGRldGVybWluZSB0aGUgbW9zdCBzdWl0YWJsZSBXR0NOQSBwYXJhbWV0ZXJzIHRvIGFwcGx5IGZvciBlYWNoIGRhdGFzZXQuIFdlIG5vdGFibHkgbmVlZCB0byBjaG9vc2UgdGhlIHNvZnQtcG93ZXIgKHNvZnQgdGhyZXNob2xkaW5nIHBvd2VyKSB3aGljaCBpcyB1c2VkIHRvIHBvd2VyIHRoZSBhZGphY2VuY3kgbWF0cml4IG9mIGdlbmVzLCBpbiBvcmRlciB0byByZWR1Y2Ugc2lnbmFsIG5vaXNlLg0KDQpBY2NvcmRpbmcgdG8gW1dHQ05BIHBhY2thZ2UgZ3VpZGVsaW5lc10oaHR0cHM6Ly9ob3J2YXRoLmdlbmV0aWNzLnVjbGEuZWR1L2h0bWwvQ29leHByZXNzaW9uTmV0d29yay9ScGFja2FnZXMvV0dDTkEvZmFxLmh0bWwpLCBpdCBpcyBub3QgcmVjb21tZW5kZWQgZmlsdGVyaW5nIGRhdGEgcHJpb3IgdG8gV0dDTkEuIEluZGVlZCwgdGhpcyBpcyBkZXNpZ25lZCB0byBiZSBhbiB1bnN1cGVydmlzZWQgYW5hbHlzaXMgbWV0aG9kIHRoYXQgY2x1c3RlcnMgZ2VuZXMgYmFzZWQgb24gdGhlaXIgZXhwcmVzc2lvbiBwcm9maWxlcyAob3IgbWV0aHlsYXRpb24gcGF0dGVybnMsIGJ5IGV4dGVuc2lvbikuIEZvciBpbnN0YW5jZSwgZmlsdGVyaW5nIGdlbmVzIGJ5IGRpZmZlcmVudGlhbCBleHByZXNzaW9uIHdvdWxkIGxlYWQgdG8gYSBzZXQgb2YgY29ycmVsYXRlZCBnZW5lcyB0aGF0IHdpbGwgZXNzZW50aWFsbHkgZm9ybSBhIGZldyBoaWdobHkgY29ycmVsYXRlZCBtb2R1bGVzLiBJdCB3b3VsZCBhbHNvIGNvbXBsZXRlbHkgaW52YWxpZGF0ZSB0aGUgc2NhbGUtZnJlZSB0b3BvbG9neSBhc3N1bXB0aW9uLCBzbyBjaG9vc2luZyBzb2Z0IHRocmVzaG9sZGluZyBwb3dlciBieSBzY2FsZS1mcmVlIHRvcG9sb2d5IGZpdCB3b3VsZCBmYWlsLiBUaGVyZWZvcmUsIHdlIHByb3ZpZGUgaW5wdXQgZGF0YSB0byB0aGUgV0dDTkEgYWxnb3JpdGhtLg0KDQpgYGBge3Igd2djbmEgZmEgZGV0ZXJtaW5lIHNvZnRwb3dlciwgZmlndXJlcy1zaWRlLCBmaWcuc2hvdz0iaG9sZCIsIG91dC53aWR0aD0iNTAlIixmaWcudG9wY2FwdGlvbiA9IFRSVUUgLCBmaWcuY2FwPSI8Y2VudGVyPioqU2V0dGluZyBwYXJhbWV0ZXJzIG9mIFdHQ05BKio8L2NlbnRlcj4ifQ0KDQojRm9yIFdHQ05BLCB3ZSB1c2UgdGhlIG5vcm1hbGl6ZWQgZXhwcmVzc2lvbiBtYXRyaXguDQoNCndnY25hX2V4cHJEYXQ9bGlzdChkbmFfdXBtX3N1YnNldCxybmFfc3Vic2V0KQ0KbmFtZXMod2djbmFfZXhwckRhdCk9YygiZG5hIiwicm5hIikNCg0Kd2djbmFfZGF0RXhwcj1sYXBwbHkod2djbmFfZXhwckRhdCx0KSAjV2UgdHJhbnNwb3NlIHRoZSBub3JtYWxpemVkIGV4cHJlc3Npb24gI21hdHJpeCwgYmVjYXVzZSBXR0NOQSBpcyB1c2VkIHRvIGZpbmQgY292YXJpYW5jZSBldHdlZW4gZ2VuZXMsIG5vdCBiZXR3ZWVuICNzYW1wbGUsIHVubGlrZSBQQ0EuDQoNCiMgQ2hvb3NlIGEgc2V0IG9mIHNvZnQtdGhyZXNob2xkaW5nIHBvd2Vycw0KcG93ZXJzID0gYygxOjIwKQ0KIyBDYWxsIHRoZSBuZXR3b3JrIHRvcG9sb2d5IGFuYWx5c2lzIGZ1bmN0aW9uDQpzZnQgPSBsYXBwbHkod2djbmFfZGF0RXhwcixwaWNrU29mdFRocmVzaG9sZCwgbmV0d29ya1R5cGUgPSAic2lnbmVkIiwgcG93ZXJWZWN0b3IgPSBwb3dlcnMsIHZlcmJvc2UgPSA1KQ0KDQojIFBsb3QgdGhlIHJlc3VsdHM6DQpwYXIobWZyb3cgPSBjKDEsIDIpKTsNCm9wdGlvbnMocmVwci5wbG90LndpZHRoID0gMTQsIHJlcHIucGxvdC5oZWlnaHQgPSAxMCk7DQoNCiMgU2NhbGUtZnJlZSB0b3BvbG9neSBmaXQgaW5kZXggYXMgYSBmdW5jdGlvbiBvZiB0aGUgc29mdC10aHJlc2hvbGRpbmcgcG93ZXINCnBsb3QubmV3KCkNCnBsb3Qoc2Z0W1siZG5hIl1dJGZpdEluZGljZXNbLDFdLCAtc2lnbihzZnRbWyJkbmEiXV0kZml0SW5kaWNlc1ssM10pKnNmdFtbImRuYSJdXSRmaXRJbmRpY2VzWywyXSwNCnhsYWIgPSAiU29mdCBUaHJlc2hvbGQgKHBvd2VyKSIsIHlsYWIgPSAiU2NhbGUgRnJlZSBUb3BvbG9neSBNb2RlbOKQow0KLOKGkkZpdCxzaWduZWQgUl4yIiwgdHlwZSA9ICJuIiwNCm1haW4gPSBwYXN0ZSgiU2NhbGUgaW5kZXBlbmRlbmNlIikpOw0KdGV4dChzZnRbWyJkbmEiXV0kZml0SW5kaWNlc1ssMV0sIC1zaWduKHNmdFtbImRuYSJdXSRmaXRJbmRpY2VzWywzXSkqc2Z0W1siZG5hIl1dJGZpdEluZGljZXNbLDJdLA0KbGFiZWxzID0gcG93ZXJzLCBjZXggPSAwLjksIGNvbCA9ICJyZWQiKTsNCiMgdGhpcyBsaW5lIGNvcnJlc3BvbmRzIHRvIHVzaW5nIGFuIFJeMiBjdXQtb2ZmIG9mIGgNCmFibGluZShoID0gMC45LCBjb2wgPSAicmVkIikNCiMgTWVhbiBjb25uZWN0aXZpdHkgYXMgYSBmdW5jdGlvbiBvZiB0aGUgc29mdC10aHJlc2hvbGRpbmcgcG93ZXINCnBsb3Qoc2Z0W1siZG5hIl1dJGZpdEluZGljZXNbLDFdLCBzZnRbWyJkbmEiXV0kZml0SW5kaWNlc1ssNV0sDQp4bGFiID0gIlNvZnQgVGhyZXNob2xkIChwb3dlcikiLCB5bGFiID0gIk1lYW4gQ29ubmVjdGl2aXR5IiwgdHlwZSA9ICJuIiwNCm1haW4gPSBwYXN0ZSgiTWVhbiBjb25uZWN0aXZpdHkiKSk7DQp0ZXh0KHNmdFtbImRuYSJdXSRmaXRJbmRpY2VzWywxXSwgc2Z0W1siZG5hIl1dJGZpdEluZGljZXNbLDVdLCBsYWJlbHMgPSBwb3dlcnMsIGNleCA9IDAuOSwgY29sID0icmVkIikNCg0KIyBTY2FsZS1mcmVlIHRvcG9sb2d5IGZpdCBpbmRleCBhcyBhIGZ1bmN0aW9uIG9mIHRoZSBzb2Z0LXRocmVzaG9sZGluZyBwb3dlcg0KcGxvdC5uZXcoKQ0KcGxvdChzZnRbWyJybmEiXV0kZml0SW5kaWNlc1ssMV0sIC1zaWduKHNmdFtbInJuYSJdXSRmaXRJbmRpY2VzWywzXSkqc2Z0W1sicm5hIl1dJGZpdEluZGljZXNbLDJdLA0KeGxhYiA9ICJTb2Z0IFRocmVzaG9sZCAocG93ZXIpIiwgeWxhYiA9ICJTY2FsZSBGcmVlIFRvcG9sb2d5IE1vZGVs4pCjDQos4oaSRml0LHNpZ25lZCBSXjIiLCB0eXBlID0gIm4iLA0KbWFpbiA9IHBhc3RlKCJTY2FsZSBpbmRlcGVuZGVuY2UiKSk7DQp0ZXh0KHNmdFtbInJuYSJdXSRmaXRJbmRpY2VzWywxXSwgLXNpZ24oc2Z0W1sicm5hIl1dJGZpdEluZGljZXNbLDNdKSpzZnRbWyJybmEiXV0kZml0SW5kaWNlc1ssMl0sDQpsYWJlbHMgPSBwb3dlcnMsIGNleCA9IDAuOSwgY29sID0gInJlZCIpOw0KIyB0aGlzIGxpbmUgY29ycmVzcG9uZHMgdG8gdXNpbmcgYW4gUl4yIGN1dC1vZmYgb2YgaA0KYWJsaW5lKGggPSAwLjksIGNvbCA9ICJyZWQiKQ0KIyBNZWFuIGNvbm5lY3Rpdml0eSBhcyBhIGZ1bmN0aW9uIG9mIHRoZSBzb2Z0LXRocmVzaG9sZGluZyBwb3dlcg0KcGxvdChzZnRbWyJybmEiXV0kZml0SW5kaWNlc1ssMV0sIHNmdFtbInJuYSJdXSRmaXRJbmRpY2VzWyw1XSwNCnhsYWIgPSAiU29mdCBUaHJlc2hvbGQgKHBvd2VyKSIsIHlsYWIgPSAiTWVhbiBDb25uZWN0aXZpdHkiLCB0eXBlID0gIm4iLA0KbWFpbiA9IHBhc3RlKCJNZWFuIGNvbm5lY3Rpdml0eSIpKTsNCnRleHQoc2Z0W1sicm5hIl1dJGZpdEluZGljZXNbLDFdLCBzZnRbWyJybmEiXV0kZml0SW5kaWNlc1ssNV0sIGxhYmVscyA9IHBvd2VycywgY2V4ID0gMC45LCBjb2wgPSJyZWQiKQ0KYGBgYA0KDQpXZSBjaG9vc2UgYSBzb2Z0LXBvd2VyIG9mIDEyIGZvciBib3RoIGRhdGFzZXRzLCBhcyB0aGlzIHlpZWxkcyBhID4gMC45IHNjYWxlLWZyZWUgdG9wb2xvZ3kgZml0dGluZyBpbmRleCAoUjxzdXA+Mjwvc3VwPikuIEludHVpdGl2ZWx5LCB3ZSB3b3VsZCBoYXZlIHJhdGhlciBjaG9zZW4gYSBzb2Z0LXBvd2VyIG9mIDQgZm9yIHRoZSBzY1BCQVQgYW5kIDcgZm9yIHRoZSBzY1JOQS1TZXEgZGF0YXNldHMsIGFzIHRoZXNlIGNvcnJlc3BvbmQgdG8gdGhlIGluZmxlY3Rpb24gcG9pbnRzIG9mIHRoZSBjdXJ2ZXMgdGhhdCBhbHNvIHlpZWxkIGEgPiAwLjkgUjxzdXA+Mjwvc3VwPi4gSG93ZXZlciwgaXQgaXMgcmVwb3J0ZWQgaW4gW1dHQ05BIHBhY2thZ2UgZ3VpZGVsaW5lc10oaHR0cHM6Ly9ob3J2YXRoLmdlbmV0aWNzLnVjbGEuZWR1L2h0bWwvQ29leHByZXNzaW9uTmV0d29yay9ScGFja2FnZXMvV0dDTkEvZmFxLmh0bWwpIHRoYXQgYSBtaW5pbXVtIHNvZnQtcG93ZXIgb2YgMTIgaXMgYWR2aXNlZCBmb3Igc2lnbmVkIG5ldHdvcmtzLiBUaGlzIHNvZnQtcG93ZXIgdGhyZXNob2xkaW5nIGFsbG93cyB0aGUgY29ycmVsYXRpb24gbWF4aW1pemF0aW9uIHdpdGggc2NhbGUtZnJlZSB0b3BvbG9neSBwcm9kdWNpbmcgbG93IG1lYW4gY29ubmVjdGl2aXR5Lg0KDQpPbmUgcGl0ZmFsbCBvZiBXR0NOQSBpcyBvdmVyZml0dGluZyB0aGUgbW9kZWwuIFRoaXMgY291bGQgaGFwcGVuIGJ5IHNldHRpbmcgc29mdC1wb3dlciB0b28gaGlnaC4NCg0KR2l2ZW4gdGhlIGhpZ2ggbnVtYmVyIG9mIGdlbmVzLCB3ZSBmaXggYSB0aHJlc2hvbGQgb2YgMTAwIGdlbmVzIHBlciBtb2R1bGUsIHRvIGF2b2lkIG92ZXItcmVzb2x1dGlvbiB5aWVsZGluZyBpbmZsYXRlZCBzbWFsbCBtb2R1bGVzLg0KDQpXR0NOQSBvbiBnZW5lIHByb21vdGVyIG1ldGh5bGF0aW9uIHByb2R1Y2VzIDUwIG1vZHVsZXMsIHdoaWxlIGl0IHlpZWxkcyAzOSBtb2R1bGVzIG9mIGNvcnJlbGF0ZWQgZ2VuZSBleHByZXNzaW9uLiBUaGUgZ3JleSBncm91cHMgY29ycmVzcG9uZCB0byBnZW5lcyB0aGF0IGhhdmUgbm90IGJlZW4gYXNzaWduZWQgdG8gYW55IG1vZHVsZS4NCg0KIyMgV0dDTkEgY2FsY3VsYXRpb24NCg0KYGBgYHtyIHdnY25hIGNvbXB1dGUsIGZpZ3VyZXMtc2lkZSwgZmlnLnNob3c9ImhvbGQiLCBvdXQud2lkdGg9IjUwJSIsZmlnLmhvbGQ9VFJVRX0NCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyN3Z2NuYSMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCg0KIyBkbmFfbmV0ID0gYmxvY2t3aXNlTW9kdWxlcyh3Z2NuYV9kYXRFeHByW1siZG5hIl1dLCBwb3dlciA9IDEyLCBtaW5Nb2R1bGVTaXplID0gMzAsIG5ldHdvcmtUeXBlID0gInNpZ25lZCIsDQojICAgICAgICAgICAgICAgICAgICAgICAgIHJlYXNzaWduVGhyZXNob2xkID0gMWUtNiwgbWVyZ2VDdXRIZWlnaHQgPSAwLjI1LA0KIyAgICAgICAgICAgICAgICAgICAgICAgICBudW1lcmljTGFiZWxzID0gVFJVRSwgcGFtUmVzcGVjdHNEZW5kcm8gPSBGQUxTRSwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgc2F2ZVRPTXMgPSBUUlVFLCBuVGhyZWFkcyA9IDEwLA0KIyAgICAgICAgICAgICAgICAgICAgICAgICBzYXZlVE9NRmlsZUJhc2UgPSAiZG5hIiwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IDAsIGNvclR5cGU9InBlYXJzb24iKQ0KIyANCiMgcm5hX25ldCA9IGJsb2Nrd2lzZU1vZHVsZXMod2djbmFfZGF0RXhwcltbInJuYSJdXSwgcG93ZXIgPSAxMiwgbWluTW9kdWxlU2l6ZSA9IDMwLCBuZXR3b3JrVHlwZSA9ICJzaWduZWQiLA0KIyAgICAgICAgICAgICAgICAgICAgICAgICByZWFzc2lnblRocmVzaG9sZCA9IDFlLTYsIG1lcmdlQ3V0SGVpZ2h0ID0gMC4yNSwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgbnVtZXJpY0xhYmVscyA9IFRSVUUsIHBhbVJlc3BlY3RzRGVuZHJvID0gRkFMU0UsDQojICAgICAgICAgICAgICAgICAgICAgICAgIHNhdmVUT01zID0gVFJVRSwgblRocmVhZHMgPSAxMCwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgc2F2ZVRPTUZpbGVCYXNlID0gInJuYSIsDQojICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSAwLCBjb3JUeXBlPSJwZWFyc29uIikNCg0KIyBzYXZlLmltYWdlKCIyMDIxXzA2XzEyX2VtYnJ5b193Z2NuYV9jb21wdXRhdGlvbi5SRGF0YSIpDQpsb2FkKCIyMDIxXzA2XzEyX2VtYnJ5b193Z2NuYV9jb21wdXRhdGlvbi5SRGF0YSIpDQoNCiMgQ29udmVydCBsYWJlbHMgdG8gY29sb3JzIGZvciBwbG90dGluZw0KZG5hX21lcmdlZF9jb2xvcnMgPSBsYWJlbHMyY29sb3JzKGRuYV9uZXQkY29sb3JzKQ0Kcm5hX21lcmdlZF9jb2xvcnMgPSBsYWJlbHMyY29sb3JzKHJuYV9uZXQkY29sb3JzKQ0KIyBQbG90IHRoZSBkZW5kcm9ncmFtIGFuZCB0aGUgbW9kdWxlIGNvbG9ycyB1bmRlcm5lYXRoDQpwbG90Lm5ldygpDQpwbG90RGVuZHJvQW5kQ29sb3JzKGRuYV9uZXQkZGVuZHJvZ3JhbXNbWzFdXSwgZG5hX21lcmdlZF9jb2xvcnNbZG5hX25ldCRibG9ja0dlbmVzW1sxXV1dLA0KICAgICAgICAgICAgICAgICAgICAiRE5BIG1ldGh5bGF0aW9uIE1vZHVsZSBjb2xvcnMiLA0KICAgICAgICAgICAgICAgICAgICBkZW5kcm9MYWJlbHMgPSBGQUxTRSwgaGFuZyA9IDAuMDMsDQogICAgICAgICAgICAgICAgICAgIGFkZEd1aWRlID0gVFJVRSwgZ3VpZGVIYW5nID0gMC4wNSkNCg0KcGxvdERlbmRyb0FuZENvbG9ycyhybmFfbmV0JGRlbmRyb2dyYW1zW1sxXV0sIHJuYV9tZXJnZWRfY29sb3JzW3JuYV9uZXQkYmxvY2tHZW5lc1tbMV1dXSwNCiAgICAgICAgICAgICAgICAgICAgIlJOQSBtZXRoeWxhdGlvbiBNb2R1bGUgY29sb3JzIiwNCiAgICAgICAgICAgICAgICAgICAgZGVuZHJvTGFiZWxzID0gRkFMU0UsIGhhbmcgPSAwLjAzLA0KICAgICAgICAgICAgICAgICAgICBhZGRHdWlkZSA9IFRSVUUsIGd1aWRlSGFuZyA9IDAuMDUpDQpgYGBgDQoNCiMjIFZpc3VhbGl6YXRpb24gb2YgV0dDTkEgbmV0d29ya3MNCg0KSW5zdGVhZCBvZiBDeXRvc2NhcGUsIHdlIHVzZSBwbG90bHkgdG8gc2VlIGl0IGluIDNELiBXaGF0IGNvdWxkIGJlIHRoZSB0aGlyZCBkaW1lbnNpb24gPyBpbnRlcmFjdGlvbiB0b28gKD8pDQoNCiMjIEdlbmUgbW9kdWxlIG1lbWJlcnNoaXAgJiBjb25uZWN0aXZpdHkNCg0KYGBgYHtyIGNhbGN1bGF0aW5nIG1lbWJlcnNoaXAgYW5kIGNvbm5lY3Rpdml0eSBvZiBnZW5lcyB0byBXR0NOQSBtb2R1bGVzLCBlY2hvPUZBTFNFfQ0KDQojR2VuZSBwcm9tb3RlciBtb2R1bGUgY29ycmVzcG9uZGVuY2UNCnByb21vdGVyX25hbWVzIDwtIGNvbG5hbWVzKHdnY25hX2RhdEV4cHJbWyJkbmEiXV0pDQpwcm9tb3Rlcl9tb2R1bGVfbmFtZXMgPC1zdWJzdHIoY24oZG5hX25ldCRNRXMpLDMsMTApDQpwcm9tb3Rlcl9tb2R1bGVzPC1kYXRhLmZyYW1lKGdlbmVfcHJvbW90ZXI9Y29sbmFtZXMod2djbmFfZGF0RXhwcltbImRuYSJdXSksTW9kdWxlPWRuYV9uZXQkY29sb3JzKQ0KDQojTWVtYmVyc2hpcCBvZiBnZW5lX3Byb21vdGVycw0KcHJvbW90ZXJfbW9kdWxlX21lbWJlcnNoaXAgPC0gYXMuZGF0YS5mcmFtZShjb3Iod2djbmFfZGF0RXhwcltbImRuYSJdXSwgZG5hX25ldCRNRXMsIHVzZSA9ICJwIikpOw0KY29sbmFtZXMocHJvbW90ZXJfbW9kdWxlX21lbWJlcnNoaXApIDwtIHByb21vdGVyX21vZHVsZV9uYW1lczsNCg0KI0Nvbm5lY3Rpdml0eQ0KcHJvbW90ZXJfbW9kdWxlX2RlZ3JlZXM9aW50cmFtb2R1bGFyQ29ubmVjdGl2aXR5LmZyb21FeHByKHdnY25hX2RhdEV4cHJbWyJkbmEiXV0sIGRuYV9uZXQkY29sb3JzLG5ldHdvcmtUeXBlID0gInNpZ25lZCIscG93ZXI9MTIpI0luLWhvdXNlIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSB0aGUgY29ubmVjdGl2aXR5IG9mIGdlbmVfcHJvbW90ZXJzIHdpdGhpbiBXR0NOQSBtb2R1bGVzLiAxMiBpcyB0aGUgc29mdC1wb3dlciB3ZSBjaG9zZSBmb3IgV0dDTkEgbW9kdWxlIGNvbXB1dGF0aW9uDQpyb3duYW1lcyhwcm9tb3Rlcl9tb2R1bGVfZGVncmVlcyk8LXByb21vdGVyX25hbWVzDQoNCmdlbmVfcHJvbW90ZXJfbW9kdWxlX21lbWJlcnNoaXAgPC0gTlVMTA0KZ2VuZV9wcm9tb3Rlcl9tb2R1bGVfbmV3X25hbWU9TlVMTA0KDQpmb3IobW9kdWxlIGluIHByb21vdGVyX21vZHVsZV9uYW1lcyApew0KICBwcm9tb3RlcnM8LXByb21vdGVyX21vZHVsZXMkZ2VuZV9wcm9tb3Rlclt3aGljaChwcm9tb3Rlcl9tb2R1bGVzJE1vZHVsZT09bW9kdWxlKV0NCiAgZDwtZGF0YS5mcmFtZShyb3cubmFtZXMgPSBwcm9tb3RlcnMsIEludHJhQ29ubmVjdGl2aXR5PXByb21vdGVyX21vZHVsZV9kZWdyZWVzW3Byb21vdGVycywia1dpdGhpbiJdLA0KICAgICAgICAgICAgICAgIEludGVyQ29ubmVjdGl2aXR5PXByb21vdGVyX21vZHVsZV9kZWdyZWVzW3Byb21vdGVycywia091dCJdLE1lbWJlcnNoaXA9cHJvbW90ZXJfbW9kdWxlX21lbWJlcnNoaXBbcHJvbW90ZXJzLG1vZHVsZV0pDQogIGdlbmVfcHJvbW90ZXJfbW9kdWxlX21lbWJlcnNoaXBbW21vZHVsZV1dPC1kW29yZGVyKGQkTWVtYmVyc2hpcCxkZWNyZWFzaW5nID0gVFJVRSksXQ0KICBnZW5lX3Byb21vdGVyX21vZHVsZV9uZXdfbmFtZT1jKGdlbmVfcHJvbW90ZXJfbW9kdWxlX25ld19uYW1lLHJvd25hbWVzKGdlbmVfcHJvbW90ZXJfbW9kdWxlX21lbWJlcnNoaXBbW21vZHVsZV1dWzEsXSkpDQp9DQoNCmthYmxlKGhlYWQoZ2VuZV9wcm9tb3Rlcl9tb2R1bGVfbWVtYmVyc2hpcFtbMV1dLDUpLGNhcHRpb24gPSAiZ2VuZV9wcm9tb3RlciBtZW1iZXJzaGlwICYgY29ubmVjdGl2aXR5IG9mIFRUQzUgbW9kdWxlIikNCg0KDQojR2VuZSB0cmFuc2NyaXB0IG1vZHVsZSBjb3JyZXNwb25kZW5jZQ0KdHJhbnNjcmlwdF9uYW1lcyA8LSBjb2xuYW1lcyh3Z2NuYV9kYXRFeHByW1sicm5hIl1dKQ0KdHJhbnNjcmlwdF9tb2R1bGVfbmFtZXMgPC1zdWJzdHIoY24ocm5hX25ldCRNRXMpLDMsMTApDQp0cmFuc2NyaXB0X21vZHVsZXM8LWRhdGEuZnJhbWUoZ2VuZV90cmFuc2NyaXB0PWNvbG5hbWVzKHdnY25hX2RhdEV4cHJbWyJybmEiXV0pLE1vZHVsZT1ybmFfbmV0JGNvbG9ycykNCg0KI01lbWJlcnNoaXAgb2YgZ2VuZV90cmFuc2NyaXB0cw0KdHJhbnNjcmlwdF9tb2R1bGVfbWVtYmVyc2hpcCA8LSBhcy5kYXRhLmZyYW1lKGNvcih3Z2NuYV9kYXRFeHByW1sicm5hIl1dLCBybmFfbmV0JE1FcywgdXNlID0gInAiKSk7DQpjb2xuYW1lcyh0cmFuc2NyaXB0X21vZHVsZV9tZW1iZXJzaGlwKSA8LSB0cmFuc2NyaXB0X21vZHVsZV9uYW1lczsNCg0KI0Nvbm5lY3Rpdml0eQ0KdHJhbnNjcmlwdF9tb2R1bGVfZGVncmVlcz1pbnRyYW1vZHVsYXJDb25uZWN0aXZpdHkuZnJvbUV4cHIod2djbmFfZGF0RXhwcltbInJuYSJdXSwgcm5hX25ldCRjb2xvcnMsbmV0d29ya1R5cGUgPSAic2lnbmVkIixwb3dlcj0xMikjSW4taG91c2UgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBjb25uZWN0aXZpdHkgb2YgZ2VuZV90cmFuc2NyaXB0cyB3aXRoaW4gV0dDTkEgbW9kdWxlcy4gMTIgaXMgdGhlIHNvZnQtcG93ZXIgd2UgY2hvc2UgZm9yIFdHQ05BIG1vZHVsZSBjb21wdXRhdGlvbg0Kcm93bmFtZXModHJhbnNjcmlwdF9tb2R1bGVfZGVncmVlcyk8LXRyYW5zY3JpcHRfbmFtZXMNCg0KZ2VuZV90cmFuc2NyaXB0X21vZHVsZV9tZW1iZXJzaGlwIDwtIE5VTEwNCmdlbmVfdHJhbnNjcmlwdF9tb2R1bGVfbmV3X25hbWU9TlVMTA0KDQpmb3IobW9kdWxlIGluIHRyYW5zY3JpcHRfbW9kdWxlX25hbWVzICl7DQogIHRyYW5zY3JpcHRzPC10cmFuc2NyaXB0X21vZHVsZXMkZ2VuZV90cmFuc2NyaXB0W3doaWNoKHRyYW5zY3JpcHRfbW9kdWxlcyRNb2R1bGU9PW1vZHVsZSldDQogIGQ8LWRhdGEuZnJhbWUocm93Lm5hbWVzID0gdHJhbnNjcmlwdHMsIEludHJhQ29ubmVjdGl2aXR5PXRyYW5zY3JpcHRfbW9kdWxlX2RlZ3JlZXNbdHJhbnNjcmlwdHMsImtXaXRoaW4iXSwNCiAgICAgICAgICAgICAgICBJbnRlckNvbm5lY3Rpdml0eT10cmFuc2NyaXB0X21vZHVsZV9kZWdyZWVzW3RyYW5zY3JpcHRzLCJrT3V0Il0sTWVtYmVyc2hpcD10cmFuc2NyaXB0X21vZHVsZV9tZW1iZXJzaGlwW3RyYW5zY3JpcHRzLG1vZHVsZV0pDQogIGdlbmVfdHJhbnNjcmlwdF9tb2R1bGVfbWVtYmVyc2hpcFtbbW9kdWxlXV08LWRbb3JkZXIoZCRNZW1iZXJzaGlwLGRlY3JlYXNpbmcgPSBUUlVFKSxdDQogIGdlbmVfdHJhbnNjcmlwdF9tb2R1bGVfbmV3X25hbWU9YyhnZW5lX3RyYW5zY3JpcHRfbW9kdWxlX25ld19uYW1lLHJvd25hbWVzKGdlbmVfdHJhbnNjcmlwdF9tb2R1bGVfbWVtYmVyc2hpcFtbbW9kdWxlXV1bMSxdKSkNCn0NCg0Ka2FibGUoaGVhZChnZW5lX3RyYW5zY3JpcHRfbW9kdWxlX21lbWJlcnNoaXBbWzFdXSw1KSxjYXB0aW9uID0gImdlbmVfdHJhbnNjcmlwdCBtZW1iZXJzaGlwICYgY29ubmVjdGl2aXR5IG9mIEFUWE4xIG1vZHVsZSIpDQoNCmBgYGANCg0KV2UgY2FsY3VsYXRlIG1lbWJlcnNoaXAgYW5kIGNvbm5lY3Rpdml0eSBvZiBtb2R1bGUgZ2VuZXMgYW5kIHJlbmFtZSBXR0NOQSBtb2R1bGVzIHdpdGggZWlnZW5nZW5lcyBkZWZpbmVkIGJ5IHRoZSBoaWdoZXN0IG1lbWJlcnNoaXAgdG8gbW9kdWxlLg0KDQojIyBDb3JyZWxhdGlvbiBoZWF0bWFwIG9mIFdHQ05BIG1vZHVsZXMgJiBkYXkgb2YgdHJlYXRtZW50IA0KDQpgYGBge3Igd2djbmEgcGxvdCBsYWJlbGVkIGhlYXRtYXAsIGZpZ3VyZXMtc2lkZSwgZmlnLnNob3c9ImhvbGQiLCBvdXQud2lkdGg9IjkwJSIsIGZpZy50b3BjYXB0aW9uID0gVFJVRSAsIGZpZy5jYXA9IjxjZW50ZXI+KipXR0NOQSBtb2R1bGVzLXRyYWl0IGNvcnJlbGF0aW9uIGhlYXRtYXAqKjwvY2VudGVyPiJ9DQoNCiMjIEROQSBtZXRoeWxhdGlvbg0KZG5hX21vZHVsZUxhYmVscyA9IGRuYV9uZXQkY29sb3JzDQpkbmFfbW9kdWxlQ29sb3JzID0gbGFiZWxzMmNvbG9ycyhkbmFfbmV0JGNvbG9ycykNCmRuYV9NRXMgPSBkbmFfbmV0JE1FczsNCmRuYV9uZXRyZWUgPSBkbmFfbmV0JGRlbmRyb2dyYW1zW1sxXV07DQoNCiMgRGVmaW5lIG51bWJlcnMgb2YgZ2VuZXMgYW5kIHNhbXBsZXMNCmRuYV9uR2VuZXMgPSBuY29sKHdnY25hX2RhdEV4cHJbWyJkbmEiXV0pOw0KZG5hX25TYW1wbGVzID0gbnJvdyh3Z2NuYV9kYXRFeHByW1siZG5hIl1dKTsNCmRuYV9NRXNfZWlnZW5nZW5lcyA9IG1vZHVsZUVpZ2VuZ2VuZXMod2djbmFfZGF0RXhwcltbImRuYSJdXSwgZG5hX21vZHVsZUxhYmVscykkZWlnZW5nZW5lcw0KDQpkbmFfTUVzX2VpZ2VuZ2VuZXM9ZG5hX01Fc19laWdlbmdlbmVzWyxjb2xuYW1lcyhkbmFfTUVzKV0NCmNvbG5hbWVzKGRuYV9NRXNfZWlnZW5nZW5lcyk9cGFzdGUwKCJNRV8iLGdlbmVfcHJvbW90ZXJfbW9kdWxlX25ld19uYW1lKQ0KY29sbmFtZXMoZG5hX01Fc19laWdlbmdlbmVzKVtsZW5ndGgoY29sbmFtZXMoZG5hX01Fc19laWdlbmdlbmVzKSldPXBhc3RlMChjb2xuYW1lcyhkbmFfTUVzX2VpZ2VuZ2VuZXMpW2xlbmd0aChjb2xuYW1lcyhkbmFfTUVzX2VpZ2VuZ2VuZXMpKV0sIl9NRTAiKSNPbiBwcsOpY2lzZSBxdWVsIGVzdCBsZSBncm91cGUgIjAiLCBxdWkgY29ycmVzcG9uZCBhdXggZ8OobmVzIG4nYXBwYXJ0ZW5hbnQgw6AgYXVjdW4gbW9kdWxlLg0KDQpkbmFfbW9kdWxlVHJhaXRDb3IgPSBjb3IoZG5hX01Fc19laWdlbmdlbmVzLCB0cmFpdHMsIHVzZSA9ICJwIik7DQpkbmFfbW9kdWxlVHJhaXRQdmFsdWUgPSBjb3JQdmFsdWVTdHVkZW50KGRuYV9tb2R1bGVUcmFpdENvciwgZG5hX25TYW1wbGVzKTsNCg0KIyBXaWxsIGRpc3BsYXkgY29ycmVsYXRpb25zIGFuZCB0aGVpciBwLXZhbHVlcw0KZG5hX3Rlc3RNYXRyaXggPSAgcGFzdGUoc2lnbmlmKGRuYV9tb2R1bGVUcmFpdENvciwgMiksICJcbigiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnbmlmKGRuYV9tb2R1bGVUcmFpdFB2YWx1ZSwgMSksICIpIiwgc2VwID0gIiIpOw0KZGltKGRuYV90ZXN0TWF0cml4KSA9IGRpbShkbmFfbW9kdWxlVHJhaXRDb3IpDQpwYXIobWFyID0gYyg2LCA4LCAxLCAxKSk7DQoNCiMgSGVhdG1hcChkbmFfbW9kdWxlVHJhaXRDb3IsY2x1c3RlcmluZ19tZXRob2Rfcm93cz0id2FyZC5EMiIsY2x1c3RlcmluZ19tZXRob2RfY29sdW1ucz0id2FyZC5EMiIpDQoNCkhlYXRtYXAoZG5hX21vZHVsZVRyYWl0Q29yWyxjKCJkYXlENiIsImRheUQ4IiwiZGF5RDEwIiwiZGF5RDEyIiwibGluZWFnZUVwaSIsImxpbmVhZ2VQRSIsImxpbmVhZ2VURSIpXSxjbHVzdGVyaW5nX21ldGhvZF9yb3dzPSJ3YXJkLkQyIixjbHVzdGVyX2NvbHVtbnMgPSBGKQ0KDQpkbmFfbW9kdWxlVHJhaXRDb3JfbWFpbiA9IGNvcihkbmFfTUVzX2VpZ2VuZ2VuZXMsIHRyYWl0c19tYWluLCB1c2UgPSAicCIpOw0KZG5hX21vZHVsZVRyYWl0UHZhbHVlX21haW4gPSBjb3JQdmFsdWVTdHVkZW50KGRuYV9tb2R1bGVUcmFpdENvcl9tYWluLCBkbmFfblNhbXBsZXMpOw0KDQojIFdpbGwgZGlzcGxheSBjb3JyZWxhdGlvbnMgYW5kIHRoZWlyIHAtdmFsdWVzDQpkbmFfdGVzdE1hdHJpeCA9ICBwYXN0ZShzaWduaWYoZG5hX21vZHVsZVRyYWl0Q29yX21haW4sIDIpLCAiXG4oIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ25pZihkbmFfbW9kdWxlVHJhaXRQdmFsdWVfbWFpbiwgMSksICIpIiwgc2VwID0gIiIpOw0KZGltKGRuYV90ZXN0TWF0cml4KSA9IGRpbShkbmFfbW9kdWxlVHJhaXRDb3JfbWFpbikNCnBhcihtYXIgPSBjKDYsIDgsIDEsIDEpKTsNCg0KSGVhdG1hcChkbmFfbW9kdWxlVHJhaXRDb3JfbWFpbixjbHVzdGVyaW5nX21ldGhvZF9yb3dzPSJ3YXJkLkQyIixjbHVzdGVyaW5nX21ldGhvZF9jb2x1bW5zPSJ3YXJkLkQyIikNCg0KIyMgUk5BDQpybmFfbW9kdWxlTGFiZWxzID0gcm5hX25ldCRjb2xvcnMNCnJuYV9tb2R1bGVDb2xvcnMgPSBsYWJlbHMyY29sb3JzKHJuYV9uZXQkY29sb3JzKQ0Kcm5hX01FcyA9IHJuYV9uZXQkTUVzOw0Kcm5hX25ldHJlZSA9IHJuYV9uZXQkZGVuZHJvZ3JhbXNbWzFdXTsNCg0KIyBEZWZpbmUgbnVtYmVycyBvZiBnZW5lcyBhbmQgc2FtcGxlcw0Kcm5hX25HZW5lcyA9IG5jb2wod2djbmFfZGF0RXhwcltbInJuYSJdXSk7DQpybmFfblNhbXBsZXMgPSBucm93KHdnY25hX2RhdEV4cHJbWyJybmEiXV0pOw0Kcm5hX01Fc19laWdlbmdlbmVzID0gbW9kdWxlRWlnZW5nZW5lcyh3Z2NuYV9kYXRFeHByW1sicm5hIl1dLCBybmFfbW9kdWxlTGFiZWxzKSRlaWdlbmdlbmVzDQoNCnJuYV9NRXNfZWlnZW5nZW5lcz1ybmFfTUVzX2VpZ2VuZ2VuZXNbLGNvbG5hbWVzKHJuYV9NRXMpXQ0KY29sbmFtZXMocm5hX01Fc19laWdlbmdlbmVzKT1wYXN0ZTAoIk1FXyIsZ2VuZV90cmFuc2NyaXB0X21vZHVsZV9uZXdfbmFtZSkNCmNvbG5hbWVzKHJuYV9NRXNfZWlnZW5nZW5lcylbbGVuZ3RoKGNvbG5hbWVzKHJuYV9NRXNfZWlnZW5nZW5lcykpXT1wYXN0ZTAoY29sbmFtZXMocm5hX01Fc19laWdlbmdlbmVzKVtsZW5ndGgoY29sbmFtZXMocm5hX01Fc19laWdlbmdlbmVzKSldLCJfTUUwIikjT24gcHLDqWNpc2UgcXVlbCBlc3QgbGUgZ3JvdXBlICIwIiwgcXVpIGNvcnJlc3BvbmQgYXV4IGfDqG5lcyBuJ2FwcGFydGVuYW50IMOgIGF1Y3VuIG1vZHVsZS4NCg0Kcm5hX21vZHVsZVRyYWl0Q29yID0gY29yKHJuYV9NRXNfZWlnZW5nZW5lcywgdHJhaXRzLCB1c2UgPSAicCIpOw0Kcm5hX21vZHVsZVRyYWl0UHZhbHVlID0gY29yUHZhbHVlU3R1ZGVudChybmFfbW9kdWxlVHJhaXRDb3IsIHJuYV9uU2FtcGxlcyk7DQoNCiMgV2lsbCBkaXNwbGF5IGNvcnJlbGF0aW9ucyBhbmQgdGhlaXIgcC12YWx1ZXMNCnJuYV90ZXN0TWF0cml4ID0gIHBhc3RlKHNpZ25pZihybmFfbW9kdWxlVHJhaXRDb3IsIDIpLCAiXG4oIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ25pZihybmFfbW9kdWxlVHJhaXRQdmFsdWUsIDEpLCAiKSIsIHNlcCA9ICIiKTsNCmRpbShybmFfdGVzdE1hdHJpeCkgPSBkaW0ocm5hX21vZHVsZVRyYWl0Q29yKQ0KcGFyKG1hciA9IGMoNiwgOCwgMSwgMSkpOw0KDQojIEhlYXRtYXAocm5hX21vZHVsZVRyYWl0Q29yLGNsdXN0ZXJpbmdfbWV0aG9kX3Jvd3M9IndhcmQuRDIiLGNsdXN0ZXJpbmdfbWV0aG9kX2NvbHVtbnM9IndhcmQuRDIiKQ0KDQpIZWF0bWFwKHJuYV9tb2R1bGVUcmFpdENvclssYygiZGF5RDYiLCJkYXlEOCIsImRheUQxMCIsImRheUQxMiIsImxpbmVhZ2VFcGkiLCJsaW5lYWdlUEUiLCJsaW5lYWdlVEUiKV0sY2x1c3RlcmluZ19tZXRob2Rfcm93cz0id2FyZC5EMiIsY2x1c3Rlcl9jb2x1bW5zID0gRikNCg0Kcm5hX21vZHVsZVRyYWl0Q29yX21haW4gPSBjb3Iocm5hX01Fc19laWdlbmdlbmVzLCB0cmFpdHNfbWFpbiwgdXNlID0gInAiKTsNCnJuYV9tb2R1bGVUcmFpdFB2YWx1ZV9tYWluID0gY29yUHZhbHVlU3R1ZGVudChybmFfbW9kdWxlVHJhaXRDb3JfbWFpbiwgcm5hX25TYW1wbGVzKTsNCg0KIyBXaWxsIGRpc3BsYXkgY29ycmVsYXRpb25zIGFuZCB0aGVpciBwLXZhbHVlcw0Kcm5hX3Rlc3RNYXRyaXggPSAgcGFzdGUoc2lnbmlmKHJuYV9tb2R1bGVUcmFpdENvcl9tYWluLCAyKSwgIlxuKCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzaWduaWYocm5hX21vZHVsZVRyYWl0UHZhbHVlX21haW4sIDEpLCAiKSIsIHNlcCA9ICIiKTsNCmRpbShybmFfdGVzdE1hdHJpeCkgPSBkaW0ocm5hX21vZHVsZVRyYWl0Q29yX21haW4pDQpwYXIobWFyID0gYyg2LCA4LCAxLCAxKSk7DQoNCkhlYXRtYXAocm5hX21vZHVsZVRyYWl0Q29yX21haW4sY2x1c3RlcmluZ19tZXRob2Rfcm93cz0id2FyZC5EMiIsY2x1c3RlcmluZ19tZXRob2RfY29sdW1ucz0id2FyZC5EMiIpDQoNCmBgYGANCg0KV2Ugb2JzZXJ2ZSB0aGF0IG1vZHVsZXMgb2YgZ2VuZSBwcm9tb3RlcnMgYW5kIHRyYW5zY3JpcHRzIGNvcnJlbGF0ZSBuaWNlbHkgd2l0aCBkZXZlbG9wbWVudCBzdGFnZSBvciBjZWxsIGxpbmVhZ2UsIHNob3dpbmcgYWxtb3N0IGV4Y2x1c2l2ZSBwYXR0ZXJucy4gDQoNCiMgSW50ZWdyYXRpb24gb2YgY29ycmVsYXRlZCBnZW5lIGFuZCBETkEgbWV0aHlsYXRpb24gbW9kdWxlcw0KDQpXZSBub3cgcGVyZm9ybSBhbiBpbnRlZ3JhdGl2ZSBhcHByb2FjaCBvbiBjb3JyZWxhdGlvbiBuZXR3b3JrcyBiZXR3ZWVuIHRoZSB0d28gZGF0YXNldHMsIHRvIGludmVzdGlnYXRlIHBvdGVudGlhbCBpbnRlcmNvbm5lY3Rpb25zIGJldHdlZW4gZ2VuZXMgYW5kIEROQSBtZXRoeWxhdGlvbiAgbW9kdWxlcy4NCg0KYGBgYHtyIHdnY25hIDIgbmV0d29ya3MgY29ycmVsYXRpb24sIGZpZ3VyZXMtc2lkZSwgZmlnLnNob3c9ImhvbGQiLCBmaWcud2lkdGg9MjAsIGZpZy5oZWlnaHQ9MjAsIG91dC53aWR0aD0iOTAlIiwgZmlnLnRvcGNhcHRpb24gPSBUUlVFICwgZmlnLmNhcD0iPGNlbnRlcj4qKk11bHRpLU9taWNzIFdHQ05BIG1vZHVsZXMgY29ycmVsYXRpb24qKjwvY2VudGVyPiJ9DQoNCmRuYV9ybmFfbW9kdWxlVHJhaXRDb3JfbWFpbiA9IGNvcihybmFfTUVzX2VpZ2VuZ2VuZXMsIGRuYV9NRXNfZWlnZW5nZW5lcywgdXNlID0gInAiKTsNCmRuYV9ybmFfbW9kdWxlVHJhaXRQdmFsdWVfbWFpbiA9IGNvclB2YWx1ZVN0dWRlbnQoZG5hX3JuYV9tb2R1bGVUcmFpdENvcl9tYWluLCBkbmFfblNhbXBsZXMpOw0KDQojIFdpbGwgZGlzcGxheSBjb3JyZWxhdGlvbnMgYW5kIHRoZWlyIHAtdmFsdWVzDQpkbmFfcm5hX3Rlc3RNYXRyaXggPSAgcGFzdGUoc2lnbmlmKGRuYV9ybmFfbW9kdWxlVHJhaXRDb3JfbWFpbiwgMiksICJcbigiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnbmlmKGRuYV9ybmFfbW9kdWxlVHJhaXRQdmFsdWVfbWFpbiwgMSksICIpIiwgc2VwID0gIiIpOw0KZGltKGRuYV9ybmFfdGVzdE1hdHJpeCkgPSBkaW0oZG5hX3JuYV9tb2R1bGVUcmFpdENvcl9tYWluKQ0KcGFyKG1hciA9IGMoNiwgOCwgMSwgMSkpOw0KDQpIZWF0bWFwKGRuYV9ybmFfbW9kdWxlVHJhaXRDb3JfbWFpbixjbHVzdGVyaW5nX21ldGhvZF9yb3dzPSJ3YXJkLkQyIixjbHVzdGVyaW5nX21ldGhvZF9jb2x1bW5zPSJ3YXJkLkQyIixuYW1lID0gIkROQS1STkEgTW9kdWxlXG5jb3JyZWxhdGlvbiIscm93X3RpdGxlPSJXR0NOQSBtb2R1bGVzIGZvciBnZW5lIGV4cHJlc3Npb24iLCByb3dfdGl0bGVfc2lkZSA9ICJyaWdodCIsIHJvd190aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSAxMy4yLCBmb250ZmFjZT0iYm9sZCIpLCByb3dfbmFtZXNfZ3AgPSBncGFyKGNvbCA9IGMoInB1cnBsZSIpKSwgY29sdW1uX3RpdGxlPSJXR0NOQSBtb2R1bGVzIGZvciBnZW5lIHByb21vdGVyIG1ldGh5bGF0aW9uIiwgY29sdW1uX3RpdGxlX3NpZGUgPSAiYm90dG9tIixjb2x1bW5fdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gMTMuMiwgZm9udGZhY2U9ImJvbGQiKSwgY29sdW1uX25hbWVzX2dwID0gZ3Bhcihjb2wgPSBjKCIjMTNkMzcwIikpKQ0KDQpkbmFfcm5hX21vZHVsZV9jb3JyZWxhdGlvbl9wb2ludHM9TlVMTA0KbmFtZXNfZG5hX3JuYV9tb2R1bGVzPU5VTEwNCg0KZm9yIChpIGluIHNlcShucm93KGRuYV9ybmFfbW9kdWxlVHJhaXRDb3JfbWFpbikpKXsNCiAgDQogIGRuYV9ybmFfbW9kdWxlX2NvcnJlbGF0aW9uX3BvaW50cz1jKGRuYV9ybmFfbW9kdWxlX2NvcnJlbGF0aW9uX3BvaW50cyxkbmFfcm5hX21vZHVsZVRyYWl0Q29yX21haW5baSxdKQ0KICANCiAgbmFtZXNfZG5hX3JuYV9tb2R1bGVzPWMobmFtZXNfZG5hX3JuYV9tb2R1bGVzLHBhc3RlMChyZXAocm93bmFtZXMoZG5hX3JuYV9tb2R1bGVUcmFpdENvcl9tYWluKVtpXSxuY29sKGRuYV9ybmFfbW9kdWxlVHJhaXRDb3JfbWFpbikpLCItIixjb2xuYW1lcyhkbmFfcm5hX21vZHVsZVRyYWl0Q29yX21haW4pKSkNCiAgDQp9DQoNCmRuYV9ybmFfbW9kdWxlX2NvcnJlbGF0aW9uX3Bsb3Q9TlVMTA0KZG5hX3JuYV9tb2R1bGVfY29ycmVsYXRpb25fcGxvdCRtb2R1bGVfcGFpcj1uYW1lc19kbmFfcm5hX21vZHVsZXMNCmRuYV9ybmFfbW9kdWxlX2NvcnJlbGF0aW9uX3Bsb3QkY29yX3ZhbHVlPWRuYV9ybmFfbW9kdWxlX2NvcnJlbGF0aW9uX3BvaW50cw0KZG5hX3JuYV9tb2R1bGVfY29ycmVsYXRpb25fcGxvdD1hcy5kYXRhLmZyYW1lKGRuYV9ybmFfbW9kdWxlX2NvcnJlbGF0aW9uX3Bsb3QpDQoNCmdncGxvdChkbmFfcm5hX21vZHVsZV9jb3JyZWxhdGlvbl9wbG90LGFlcyh4PW1vZHVsZV9wYWlyLCB5PWNvcl92YWx1ZSwgbGFiZWw9bW9kdWxlX3BhaXIpKSsNCiAgZ2VvbV9wb2ludCgpKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsPWlmZWxzZShjb3JfdmFsdWUgPiAwLjUsbW9kdWxlX3BhaXIsJycpKSxoanVzdD0wLHZqdXN0PTApKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MC41LCBsaW5ldHlwZT0ic29saWQiLCANCiAgICAgICAgICAgICAgICBjb2xvciA9ICJyZWQiLCBzaXplPTEpDQoNCmBgYGANCg0KDQpXZSBzZWxlY3QgdGhlIHRvcCBtb3N0IGNvcnJlbGF0ZWQgb3IgYW50aS1jb3JyZWxhdGVkIGdlbmUgcHJvbW90ZXIgYW5kIHRyYW5zY3JpcHQgbW9kdWxlcyBmb3IgZnVydGhlciBpbnZlc3RpZ2F0aW9uLiBXZSBmb3VjcyBvbiAzIHBhaXJzIG9mIHRvcCBjb3JyZWxhdGVkIHRyYW5zY3JpcHQtcG9tb3RlciBtb2R1bGVzLCB0aGF0IGNoYXJhY3Rlcml6ZSBzb21lIGxpbmVhZ2Utc3RhZ2UgdHJhaXRzOg0KDQotIE1FX1JQUzIzLU1FX1NOT1JEMTE2LjggKEVwaS1kYXk2KQ0KLSBNRV9WV0NFLU1FX1NQQUNBNUIgKFBFLWRheTgpDQotIE1FX1VCRTJFMi1NRV9NWEkxIChURS1kYXk4KQ0KDQpjby1leHByZXNzaW9uIHNpbWlsYXJpdHkgYW5kICJjby1tZXRoeWxhdGlvbiBzaW1pbGFyaXR5Ig0KDQojIyBWaXN1YWxpemF0aW9uIG9mIFdHQ05BIG1vZHVsZSBuZXR3b3JrIHdpdGggQ3l0b3NjYXBlDQoNCiMjIEZ1bmN0aW9uYWwgZW5yaWNobWVudCBvbiBXR0NOQSBzZWxlY3RlZCBtb2R1bGVzDQoNCldlIHNldCBhIHAtdmFsdWUgdGhyZXNob2xkIG9mIDAuMSBmb3Igc2lnbmlmaWNhbnQgcHJvY2VzcyBlbnJpY2htZW50LCBhcyBtb2R1bGVzIH4gNDAgZ2VuZXMgZmFpbHMgdG8gcHJvZHVjZSBzaWduaWZpY2FudCByZXN1bHRzIHVuZGVyIGEgMC4wNSB0aHJlc2hvbGQuDQoNCmBgYGB7ciBHTyBhbmFseXNpcyBybmEgYW5kIGRuYSB3aXRoIGdvc3QsIGZpZy50b3BjYXB0aW9uID0gVFJVRSAsIGZpZy5jYXA9IjxjZW50ZXI+KipHZW5lIE9udG9sb2d5IGFuYWx5c2lzIG9mIFdHQ05BIG1vZHVsZSBnZW5lIHRyYW5zY3JpcHRzIGFuZCBnZW5lIHByb21vdGVycyoqPC9jZW50ZXI+IiwgZmlnLmhvbGQ9VFJVRX0NCiMgV2UgZ2V0IHRoZSBnZW5lcyBmcm9tIHNlbGVjdGVkIFdHQ05BIG1vZHVsZXMNCmdlbmVfcHJvbW90ZXJfbW9kdWxlX21lbWJlcnNoaXBfZ289Z2VuZV9wcm9tb3Rlcl9tb2R1bGVfbWVtYmVyc2hpcA0KbmFtZXMoZ2VuZV9wcm9tb3Rlcl9tb2R1bGVfbWVtYmVyc2hpcF9nbyk9Z2VuZV9wcm9tb3Rlcl9tb2R1bGVfbmV3X25hbWUNCg0KZ2VuZV90cmFuc2NyaXB0X21vZHVsZV9tZW1iZXJzaGlwX2dvPWdlbmVfdHJhbnNjcmlwdF9tb2R1bGVfbWVtYmVyc2hpcA0KbmFtZXMoZ2VuZV90cmFuc2NyaXB0X21vZHVsZV9tZW1iZXJzaGlwX2dvKT1nZW5lX3RyYW5zY3JpcHRfbW9kdWxlX25ld19uYW1lDQoNCm1vZHVsZV9wcm9tb3RlcnNfZXBpX2Q2IDwtIHJvd25hbWVzKGdlbmVfcHJvbW90ZXJfbW9kdWxlX21lbWJlcnNoaXBfZ29bWyJTVEFSRDEwIl1dKQ0KbW9kdWxlX3RyYW5zY3JpcHRzX2VwaV9kNiA8LSByb3duYW1lcyhnZW5lX3RyYW5zY3JpcHRfbW9kdWxlX21lbWJlcnNoaXBfZ29bWyJSUDlQIl1dKQ0KDQoNCm1vZHVsZV9wcm9tb3RlcnNfcGVfZDggPC0gcm93bmFtZXMoZ2VuZV9wcm9tb3Rlcl9tb2R1bGVfbWVtYmVyc2hpcF9nb1tbIlNQQUNBNUIiXV0pDQptb2R1bGVfdHJhbnNjcmlwdHNfcGVfZDggPC0gcm93bmFtZXMoZ2VuZV90cmFuc2NyaXB0X21vZHVsZV9tZW1iZXJzaGlwX2dvW1siVldDRSJdXSkNCg0KbW9kdWxlX3Byb21vdGVyc190ZV9kNiA8LSByb3duYW1lcyhnZW5lX3Byb21vdGVyX21vZHVsZV9tZW1iZXJzaGlwX2dvW1siU05PUkQ3NiJdXSkNCm1vZHVsZV90cmFuc2NyaXB0c190ZV9kNiA8LSByb3duYW1lcyhnZW5lX3RyYW5zY3JpcHRfbW9kdWxlX21lbWJlcnNoaXBfZ29bWyJXTlQ3QiJdXSkNCg0KYGBgYA0KDQojIE5ldHdvcmsgdmlzdWFsaXphdGlvbg0KDQpBcyB0aGV5IGFyZSB0aGUgbWFpbiBkcml2ZXJzIG9mIGNlbGwgZmF0ZSBwcm9ncmVzc2lvbiwgd2UgZm9jdXMgb24gdHJhbnNjcmlwdGlvbiBmYWN0b3IgaW50ZXJhY3Rpb25zLiBXZSBxdWVyeSB0aGUgW1RGMkROQSBkYXRhYmFzZV0oaHR0cDovL2Zpc2VybGFiLm9yZy90ZjJkbmFfZGIvL2luZGV4Lmh0bWwpIG9uIGNvbXB1dGVkIGludGVyYWN0aW9ucyBpbiBodW1hbiBiYXNlZCBvbiBETkEgYmluZGluZyBtb3RpdmVzLiBUcmFuc2NyaXB0aW9uIGZhY3RvcnMgYXJlIHByZWNlZGVkIHdpdGggdGhlICJURiIgc3ltYm9sIGFuZCB5aWVsZCBhIGxpc3Qgb2YgcmVndWxhdGVkIGdlbmVzIHRoZXkgaW50ZXJhY3Qgd2l0aCwgd2hpbGUgb3RoZXIgY2xhc3NlcyBvZiBnZW5lcyBkbyBub3QuDQoNCmBgYGB7ciBxdWVyeSBtdWx0aXBsZSBnZW5lcyB0byBTVFJJTkcgaW50ZXJhY3Rpb24gZGF0YWJhc2V9DQoNCiMgZmFzdFdyaXRlKGMobW9kdWxlX3Byb21vdGVyc19lcGlfZDYsbW9kdWxlX3RyYW5zY3JpcHRzX2VwaV9kNiksZmlsZT0ibW9kdWxlX3Byb21vdGVyc19tb2R1bGVfdHJhbnNjcmlwdHNfZXBpX2Q2LnR4dCIsY29sLm5hbWVzID0gRikNCiMgZmFzdFdyaXRlKGMobW9kdWxlX3Byb21vdGVyc19wZV9kOCxtb2R1bGVfdHJhbnNjcmlwdHNfcGVfZDgpLGZpbGU9Im1vZHVsZV9wcm9tb3RlcnNfbW9kdWxlX3RyYW5zY3JpcHRzX3BlX2Q4LnR4dCIsY29sLm5hbWVzID0gRikNCiMgZmFzdFdyaXRlKGMobW9kdWxlX3Byb21vdGVyc190ZV9kNixtb2R1bGVfdHJhbnNjcmlwdHNfdGVfZDYpLGZpbGU9Im1vZHVsZV9wcm9tb3RlcnNfbW9kdWxlX3RyYW5zY3JpcHRzX3RlX2Q2LnR4dCIsY29sLm5hbWVzID0gRikNCg0KZXBpX2ludGVyYWN0aW9uX2ZpbGVzID0gbGlzdC5maWxlcyhwYXR0ZXJuPSJeZXBpX2Q2XyoiKQ0Kc3ViMT1zdWIoIl5bZXBpX2Q2X10rKCopIiwgIlxcMSIsIGVwaV9pbnRlcmFjdGlvbl9maWxlcykNCnN1YjI9c3ViKCJcXC5jc3YuKiIsICIiLCBzdWIxKQ0KZXBpX21vZHVsZV9pbnRlcmFjdGlvbnMgPSBsYXBwbHkoZXBpX2ludGVyYWN0aW9uX2ZpbGVzLCBmYXN0UmVhZDIpDQpuYW1lcyhlcGlfbW9kdWxlX2ludGVyYWN0aW9ucyk9c3ViMg0KDQpwZV9pbnRlcmFjdGlvbl9maWxlcyA9IGxpc3QuZmlsZXMocGF0dGVybj0iXnBlX2Q4XyoiKQ0Kc3ViMT1zdWIoIl5bcGVfZDhfXSsoKikiLCAiXFwxIiwgcGVfaW50ZXJhY3Rpb25fZmlsZXMpDQpzdWIyPXN1YigiXFwuY3N2LioiLCAiIiwgc3ViMSkNCnBlX21vZHVsZV9pbnRlcmFjdGlvbnMgPSBsYXBwbHkocGVfaW50ZXJhY3Rpb25fZmlsZXMsIGZhc3RSZWFkMikNCm5hbWVzKHBlX21vZHVsZV9pbnRlcmFjdGlvbnMpPXN1YjINCg0KdGVfaW50ZXJhY3Rpb25fZmlsZXMgPSBsaXN0LmZpbGVzKHBhdHRlcm49Il50ZV9kNl8qIikNCnN1YjE9c3ViKCJeW3RlX2Q2X10rKCopIiwgIlxcMSIsIHRlX2ludGVyYWN0aW9uX2ZpbGVzKQ0Kc3ViMj1zdWIoIlxcLmNzdi4qIiwgIiIsIHN1YjEpDQp0ZV9tb2R1bGVfaW50ZXJhY3Rpb25zID0gbGFwcGx5KHRlX2ludGVyYWN0aW9uX2ZpbGVzLCBmYXN0UmVhZDIpDQpuYW1lcyh0ZV9tb2R1bGVfaW50ZXJhY3Rpb25zKT1zdWIyDQoNCmVwaV9kNl9kbmFfcm5hX21vZHVsZV9pbnRlcmFjdGlvbj1OVUxMDQplcGlfZDZfaW50ZXJhY3Rpb25fZGY9TlVMTA0KZm9yIChpIGluIG5hbWVzKGVwaV9tb2R1bGVfaW50ZXJhY3Rpb25zKSl7DQogIGVwaV9kNl9kbmFfcm5hX21vZHVsZV9pbnRlcmFjdGlvbltbaV1dPWNiaW5kKHNvdXJjZV9ub2RlPXJlcChuYW1lcyhlcGlfbW9kdWxlX2ludGVyYWN0aW9uc1tpXSksbnJvdyhlcGlfbW9kdWxlX2ludGVyYWN0aW9uc1tbaV1dKSksdGFyZ2V0X25vZGU9cm93bmFtZXMoZXBpX21vZHVsZV9pbnRlcmFjdGlvbnNbW2ldXSkscF92YWx1ZT1lcGlfbW9kdWxlX2ludGVyYWN0aW9uc1tbaV1dJHBfdmFsdWUsY2hyb21vc29tZT1lcGlfbW9kdWxlX2ludGVyYWN0aW9uc1tbaV1dJGNocm9tb3NvbWVfbmFtZSxkb3duc3RyZWFtX2dlbmU9ZXBpX21vZHVsZV9pbnRlcmFjdGlvbnNbW2ldXSRkb3duc3RyZWFtKQ0KDQogIGVwaV9kNl9pbnRlcmFjdGlvbl9kZj1yYmluZChlcGlfZDZfaW50ZXJhY3Rpb25fZGYsZXBpX2Q2X2RuYV9ybmFfbW9kdWxlX2ludGVyYWN0aW9uW1tpXV0pDQp9DQoNCnBlX2Q4X2RuYV9ybmFfbW9kdWxlX2ludGVyYWN0aW9uPU5VTEwNCnBlX2Q4X2ludGVyYWN0aW9uX2RmPU5VTEwNCmZvciAoaSBpbiBuYW1lcyhwZV9tb2R1bGVfaW50ZXJhY3Rpb25zKSl7DQogIHBlX2Q4X2RuYV9ybmFfbW9kdWxlX2ludGVyYWN0aW9uW1tpXV09Y2JpbmQoc291cmNlX25vZGU9cmVwKG5hbWVzKHBlX21vZHVsZV9pbnRlcmFjdGlvbnNbaV0pLG5yb3cocGVfbW9kdWxlX2ludGVyYWN0aW9uc1tbaV1dKSksdGFyZ2V0X25vZGU9cm93bmFtZXMocGVfbW9kdWxlX2ludGVyYWN0aW9uc1tbaV1dKSxwX3ZhbHVlPXBlX21vZHVsZV9pbnRlcmFjdGlvbnNbW2ldXSRwX3ZhbHVlLGNocm9tb3NvbWU9cGVfbW9kdWxlX2ludGVyYWN0aW9uc1tbaV1dJGNocm9tb3NvbWVfbmFtZSxkb3duc3RyZWFtX2dlbmU9cGVfbW9kdWxlX2ludGVyYWN0aW9uc1tbaV1dJGRvd25zdHJlYW0pDQoNCiAgcGVfZDhfaW50ZXJhY3Rpb25fZGY9cmJpbmQocGVfZDhfaW50ZXJhY3Rpb25fZGYscGVfZDhfZG5hX3JuYV9tb2R1bGVfaW50ZXJhY3Rpb25bW2ldXSkNCn0NCg0KdGVfZDZfZG5hX3JuYV9tb2R1bGVfaW50ZXJhY3Rpb249TlVMTA0KdGVfZDZfaW50ZXJhY3Rpb25fZGY9TlVMTA0KZm9yIChpIGluIG5hbWVzKHRlX21vZHVsZV9pbnRlcmFjdGlvbnMpKXsNCiAgdGVfZDZfZG5hX3JuYV9tb2R1bGVfaW50ZXJhY3Rpb25bW2ldXT1jYmluZChzb3VyY2Vfbm9kZT1yZXAobmFtZXModGVfbW9kdWxlX2ludGVyYWN0aW9uc1tpXSksbnJvdyh0ZV9tb2R1bGVfaW50ZXJhY3Rpb25zW1tpXV0pKSx0YXJnZXRfbm9kZT1yb3duYW1lcyh0ZV9tb2R1bGVfaW50ZXJhY3Rpb25zW1tpXV0pLHBfdmFsdWU9dGVfbW9kdWxlX2ludGVyYWN0aW9uc1tbaV1dJHBfdmFsdWUsY2hyb21vc29tZT10ZV9tb2R1bGVfaW50ZXJhY3Rpb25zW1tpXV0kY2hyb21vc29tZV9uYW1lLGRvd25zdHJlYW1fZ2VuZT10ZV9tb2R1bGVfaW50ZXJhY3Rpb25zW1tpXV0kZG93bnN0cmVhbSkNCg0KICB0ZV9kNl9pbnRlcmFjdGlvbl9kZj1yYmluZCh0ZV9kNl9pbnRlcmFjdGlvbl9kZix0ZV9kNl9kbmFfcm5hX21vZHVsZV9pbnRlcmFjdGlvbltbaV1dKQ0KfQ0KDQplcGlfZDZfZG5hX2FkamFjZW5jeSA8LSBhZGphY2VuY3kod2djbmFfZGF0RXhwcltbImRuYSJdXSwNCnNlbGVjdENvbHMgPSBOVUxMLA0KdHlwZSA9ICJzaWduZWQiLA0KcG93ZXIgPSAxMiwgI3NldCBzb2Z0LXBvd2VyIHRvIDEyIGFzIGZvciBtb2R1bGUgY29tcHV0YXRpb24NCmNvckZuYyA9ICJjb3IiLCBjb3JPcHRpb25zID0gbGlzdCh1c2UgPSAicCIpLA0Kd2VpZ2h0cyA9IE5VTEwsDQpkaXN0Rm5jID0gImRpc3QiLCBkaXN0T3B0aW9ucyA9ICJtZXRob2QgPSAnd2FyZC5EMiciLA0Kd2VpZ2h0QXJnTmFtZXMgPSBjKCJ3ZWlnaHRzLngiLCAid2VpZ2h0cy55IikpDQoNCmVwaV9kNl9ybmFfYWRqYWNlbmN5IDwtIGFkamFjZW5jeSh3Z2NuYV9kYXRFeHByW1sicm5hIl1dLA0Kc2VsZWN0Q29scyA9IE5VTEwsDQp0eXBlID0gInNpZ25lZCIsDQpwb3dlciA9IDEyLCAjc2V0IHNvZnQtcG93ZXIgdG8gMTIgYXMgZm9yIG1vZHVsZSBjb21wdXRhdGlvbg0KY29yRm5jID0gImNvciIsIGNvck9wdGlvbnMgPSBsaXN0KHVzZSA9ICJwIiksDQp3ZWlnaHRzID0gTlVMTCwNCmRpc3RGbmMgPSAiZGlzdCIsIGRpc3RPcHRpb25zID0gIm1ldGhvZCA9ICd3YXJkLkQyJyIsDQp3ZWlnaHRBcmdOYW1lcyA9IGMoIndlaWdodHMueCIsICJ3ZWlnaHRzLnkiKSkNCg0KcGVfZDhfZG5hX2FkamFjZW5jeSA8LSBhZGphY2VuY3kod2djbmFfZGF0RXhwcltbImRuYSJdXSwNCnNlbGVjdENvbHMgPSBOVUxMLA0KdHlwZSA9ICJzaWduZWQiLA0KcG93ZXIgPSAxMiwgI3NldCBzb2Z0LXBvd2VyIHRvIDEyIGFzIGZvciBtb2R1bGUgY29tcHV0YXRpb24NCmNvckZuYyA9ICJjb3IiLCBjb3JPcHRpb25zID0gbGlzdCh1c2UgPSAicCIpLA0Kd2VpZ2h0cyA9IE5VTEwsDQpkaXN0Rm5jID0gImRpc3QiLCBkaXN0T3B0aW9ucyA9ICJtZXRob2QgPSAnd2FyZC5EMiciLA0Kd2VpZ2h0QXJnTmFtZXMgPSBjKCJ3ZWlnaHRzLngiLCAid2VpZ2h0cy55IikpDQoNCnBlX2Q4X3JuYV9hZGphY2VuY3kgPC0gYWRqYWNlbmN5KHdnY25hX2RhdEV4cHJbWyJybmEiXV0sDQpzZWxlY3RDb2xzID0gTlVMTCwNCnR5cGUgPSAic2lnbmVkIiwNCnBvd2VyID0gMTIsICNzZXQgc29mdC1wb3dlciB0byAxMiBhcyBmb3IgbW9kdWxlIGNvbXB1dGF0aW9uDQpjb3JGbmMgPSAiY29yIiwgY29yT3B0aW9ucyA9IGxpc3QodXNlID0gInAiKSwNCndlaWdodHMgPSBOVUxMLA0KZGlzdEZuYyA9ICJkaXN0IiwgZGlzdE9wdGlvbnMgPSAibWV0aG9kID0gJ3dhcmQuRDInIiwNCndlaWdodEFyZ05hbWVzID0gYygid2VpZ2h0cy54IiwgIndlaWdodHMueSIpKQ0KDQp0ZV9kNl9kbmFfYWRqYWNlbmN5IDwtIGFkamFjZW5jeSh3Z2NuYV9kYXRFeHByW1siZG5hIl1dLA0Kc2VsZWN0Q29scyA9IE5VTEwsDQp0eXBlID0gInNpZ25lZCIsDQpwb3dlciA9IDEyLCAjc2V0IHNvZnQtcG93ZXIgdG8gMTIgYXMgZm9yIG1vZHVsZSBjb21wdXRhdGlvbg0KY29yRm5jID0gImNvciIsIGNvck9wdGlvbnMgPSBsaXN0KHVzZSA9ICJwIiksDQp3ZWlnaHRzID0gTlVMTCwNCmRpc3RGbmMgPSAiZGlzdCIsIGRpc3RPcHRpb25zID0gIm1ldGhvZCA9ICd3YXJkLkQyJyIsDQp3ZWlnaHRBcmdOYW1lcyA9IGMoIndlaWdodHMueCIsICJ3ZWlnaHRzLnkiKSkNCg0KdGVfZDZfcm5hX2FkamFjZW5jeSA8LSBhZGphY2VuY3kod2djbmFfZGF0RXhwcltbInJuYSJdXSwNCnNlbGVjdENvbHMgPSBOVUxMLA0KdHlwZSA9ICJzaWduZWQiLA0KcG93ZXIgPSAxMiwgI3NldCBzb2Z0LXBvd2VyIHRvIDEyIGFzIGZvciBtb2R1bGUgY29tcHV0YXRpb24NCmNvckZuYyA9ICJjb3IiLCBjb3JPcHRpb25zID0gbGlzdCh1c2UgPSAicCIpLA0Kd2VpZ2h0cyA9IE5VTEwsDQpkaXN0Rm5jID0gImRpc3QiLCBkaXN0T3B0aW9ucyA9ICJtZXRob2QgPSAnd2FyZC5EMiciLA0Kd2VpZ2h0QXJnTmFtZXMgPSBjKCJ3ZWlnaHRzLngiLCAid2VpZ2h0cy55IikpDQoNCmBgYGANCg0KDQpgYGBge3Igc2VsZWN0ZWQgZ2VucyBhZGphYyBtYXRyaXh9DQoNCmVwaV9kNl9kbmFfYWRqYWNlbmN5X3NlbGVjdGVkPWVwaV9kNl9kbmFfYWRqYWNlbmN5W21vZHVsZV9wcm9tb3RlcnNfZXBpX2Q2LG1vZHVsZV9wcm9tb3RlcnNfZXBpX2Q2XQ0KZXBpX2Q2X3JuYV9hZGphY2VuY3lfc2VsZWN0ZWQ9ZXBpX2Q2X3JuYV9hZGphY2VuY3lbbW9kdWxlX3RyYW5zY3JpcHRzX2VwaV9kNixtb2R1bGVfdHJhbnNjcmlwdHNfZXBpX2Q2XQ0KDQpwZV9kOF9kbmFfYWRqYWNlbmN5X3NlbGVjdGVkPXBlX2Q4X2RuYV9hZGphY2VuY3lbbW9kdWxlX3Byb21vdGVyc19wZV9kOCxtb2R1bGVfcHJvbW90ZXJzX3BlX2Q4XQ0KcGVfZDhfcm5hX2FkamFjZW5jeV9zZWxlY3RlZD1wZV9kOF9ybmFfYWRqYWNlbmN5W21vZHVsZV90cmFuc2NyaXB0c19wZV9kOCxtb2R1bGVfdHJhbnNjcmlwdHNfcGVfZDhdDQoNCnRlX2Q2X2RuYV9hZGphY2VuY3lfc2VsZWN0ZWQ9dGVfZDZfZG5hX2FkamFjZW5jeVttb2R1bGVfcHJvbW90ZXJzX3RlX2Q2LG1vZHVsZV9wcm9tb3RlcnNfdGVfZDZdDQp0ZV9kNl9ybmFfYWRqYWNlbmN5X3NlbGVjdGVkPXRlX2Q2X3JuYV9hZGphY2VuY3lbbW9kdWxlX3RyYW5zY3JpcHRzX3RlX2Q2LG1vZHVsZV90cmFuc2NyaXB0c190ZV9kNl0NCg0KYGBgYA0KDQpgYGBge3IgYXR0ZW1wdCB0byBuZXR3b3JrfQ0KDQptb2R1bGVfcHJvbW90ZXJzX2VwaV9kNl9jb29yZD1OVUxMDQptb2R1bGVfcHJvbW90ZXJzX2VwaV9kNl9jb29yZCRzb3VyY2Vfbm9kZT1tb2R1bGVfcHJvbW90ZXJzX2VwaV9kNg0KbW9kdWxlX3Byb21vdGVyc19lcGlfZDZfY29vcmQkeF9zb3VyY2U9cmVwKDEsbGVuZ3RoKG1vZHVsZV9wcm9tb3RlcnNfZXBpX2Q2KSkNCm1vZHVsZV9wcm9tb3RlcnNfZXBpX2Q2X2Nvb3JkJHlfc291cmNlPXNlcSh0bz0oMTAwL2xlbmd0aChtb2R1bGVfcHJvbW90ZXJzX2VwaV9kNikpLCBmcm9tPTEwMCwgYnk9LSgxMDAvbGVuZ3RoKG1vZHVsZV9wcm9tb3RlcnNfZXBpX2Q2KSkpDQptb2R1bGVfcHJvbW90ZXJzX2VwaV9kNl9jb29yZD1hcy5kYXRhLmZyYW1lKG1vZHVsZV9wcm9tb3RlcnNfZXBpX2Q2X2Nvb3JkLGNvbC5uYW1lcz1uYW1lcyhtb2R1bGVfcHJvbW90ZXJzX2VwaV9kNl9jb29yZCkpDQoNCm1vZHVsZV90cmFuc2NyaXB0c19lcGlfZDZfY29vcmQ9TlVMTA0KbW9kdWxlX3RyYW5zY3JpcHRzX2VwaV9kNl9jb29yZCRzb3VyY2Vfbm9kZT1tb2R1bGVfdHJhbnNjcmlwdHNfZXBpX2Q2DQptb2R1bGVfdHJhbnNjcmlwdHNfZXBpX2Q2X2Nvb3JkJHhfc291cmNlPXJlcCgyLGxlbmd0aChtb2R1bGVfdHJhbnNjcmlwdHNfZXBpX2Q2KSkNCm1vZHVsZV90cmFuc2NyaXB0c19lcGlfZDZfY29vcmQkeV9zb3VyY2U9c2VxKHRvPSgxMDAvbGVuZ3RoKG1vZHVsZV90cmFuc2NyaXB0c19lcGlfZDYpKSwgZnJvbT0xMDAsIGJ5PS0oMTAwL2xlbmd0aChtb2R1bGVfdHJhbnNjcmlwdHNfZXBpX2Q2KSkpDQptb2R1bGVfdHJhbnNjcmlwdHNfZXBpX2Q2X2Nvb3JkPWFzLmRhdGEuZnJhbWUobW9kdWxlX3RyYW5zY3JpcHRzX2VwaV9kNl9jb29yZCxjb2wubmFtZXM9bmFtZXMobW9kdWxlX3RyYW5zY3JpcHRzX2VwaV9kNl9jb29yZCkpDQoNCmVwaV9tb2R1bGVzX2Nvb3JkPXJiaW5kKG1vZHVsZV9wcm9tb3RlcnNfZXBpX2Q2X2Nvb3JkLG1vZHVsZV90cmFuc2NyaXB0c19lcGlfZDZfY29vcmQpDQoNCg0KZXBpX2Q2X21vZHVsZV9hcnJvd3M9TlVMTA0KDQogIA0KZXBpX2Fycm93X2RuYV9kbmE9ZXBpX2Q2X2ludGVyYWN0aW9uX2RmW2VwaV9kNl9pbnRlcmFjdGlvbl9kZlssInNvdXJjZV9ub2RlIl0laW4lbW9kdWxlX3Byb21vdGVyc19lcGlfZDYgJiBlcGlfZDZfaW50ZXJhY3Rpb25fZGZbLCJ0YXJnZXRfbm9kZSJdJWluJW1vZHVsZV9wcm9tb3RlcnNfZXBpX2Q2LF0NCmVwaV9hcnJvd19kbmFfZG5hPWNiaW5kKGVwaV9hcnJvd19kbmFfZG5hLHhfYXJyb3c9cmVwKDEuMTMsbnJvdyhlcGlfYXJyb3dfZG5hX2RuYSkpLHhlbmRfYXJyb3c9cmVwKDEuMTMsbnJvdyhlcGlfYXJyb3dfZG5hX2RuYSkpKQ0KDQp5PU5VTEwNCg0KZm9yIChpIGluIGVwaV9hcnJvd19kbmFfZG5hWywic291cmNlX25vZGUiXSl7DQogIA0KICB5PWMoeSxtb2R1bGVfcHJvbW90ZXJzX2VwaV9kNl9jb29yZCR5X3NvdXJjZVttb2R1bGVfcHJvbW90ZXJzX2VwaV9kNl9jb29yZCRzb3VyY2Vfbm9kZT09aV0pICANCiAgDQp9DQoNCnllbmQ9TlVMTA0KDQpmb3IgKGkgaW4gZXBpX2Fycm93X2RuYV9kbmFbLCJ0YXJnZXRfbm9kZSJdKXsNCiAgDQogIHllbmQ9Yyh5ZW5kLG1vZHVsZV9wcm9tb3RlcnNfZXBpX2Q2X2Nvb3JkJHlfc291cmNlW21vZHVsZV9wcm9tb3RlcnNfZXBpX2Q2X2Nvb3JkJHNvdXJjZV9ub2RlPT1pXSkgIA0KICANCn0NCg0KZXBpX2Fycm93X2RuYV9kbmE9Y2JpbmQoZXBpX2Fycm93X2RuYV9kbmEseV9hcnJvdz15LHllbmRfYXJyb3c9eWVuZCkNCg0KZXBpX2Fycm93X2RuYV9ybmE9ZXBpX2Q2X2ludGVyYWN0aW9uX2RmW2VwaV9kNl9pbnRlcmFjdGlvbl9kZlssInNvdXJjZV9ub2RlIl0laW4lbW9kdWxlX3Byb21vdGVyc19lcGlfZDYgJiBlcGlfZDZfaW50ZXJhY3Rpb25fZGZbLCJ0YXJnZXRfbm9kZSJdJWluJW1vZHVsZV90cmFuc2NyaXB0c19lcGlfZDYsXQ0KZXBpX2Fycm93X2RuYV9ybmE9Y2JpbmQoZXBpX2Fycm93X2RuYV9ybmEseF9hcnJvdz1yZXAoMS4xMyxucm93KGVwaV9hcnJvd19kbmFfcm5hKSkseGVuZF9hcnJvdz1yZXAoMS45OCxucm93KGVwaV9hcnJvd19kbmFfcm5hKSkpDQoNCnk9TlVMTA0KDQpmb3IgKGkgaW4gZXBpX2Fycm93X2RuYV9ybmFbLCJzb3VyY2Vfbm9kZSJdKXsNCiAgDQogIHk9Yyh5LG1vZHVsZV9wcm9tb3RlcnNfZXBpX2Q2X2Nvb3JkJHlfc291cmNlW21vZHVsZV9wcm9tb3RlcnNfZXBpX2Q2X2Nvb3JkJHNvdXJjZV9ub2RlPT1pXSkgIA0KICANCn0NCg0KeWVuZD1OVUxMDQoNCmZvciAoaSBpbiBlcGlfYXJyb3dfZG5hX3JuYVssInRhcmdldF9ub2RlIl0pew0KICANCiAgeWVuZD1jKHllbmQsbW9kdWxlX3RyYW5zY3JpcHRzX2VwaV9kNl9jb29yZCR5X3NvdXJjZVttb2R1bGVfdHJhbnNjcmlwdHNfZXBpX2Q2X2Nvb3JkJHNvdXJjZV9ub2RlPT1pXSkgIA0KICANCn0NCg0KZXBpX2Fycm93X2RuYV9ybmE9Y2JpbmQoZXBpX2Fycm93X2RuYV9ybmEseV9hcnJvdz15LHllbmRfYXJyb3c9eWVuZCkNCg0KZXBpX2Fycm93X3JuYV9ybmE9ZXBpX2Q2X2ludGVyYWN0aW9uX2RmW2VwaV9kNl9pbnRlcmFjdGlvbl9kZlssInNvdXJjZV9ub2RlIl0laW4lbW9kdWxlX3RyYW5zY3JpcHRzX2VwaV9kNiAmIGVwaV9kNl9pbnRlcmFjdGlvbl9kZlssInRhcmdldF9ub2RlIl0laW4lbW9kdWxlX3RyYW5zY3JpcHRzX2VwaV9kNixdDQplcGlfYXJyb3dfcm5hX3JuYT1jYmluZChlcGlfYXJyb3dfcm5hX3JuYSx4X2Fycm93PXJlcCgxLjk4LG5yb3coZXBpX2Fycm93X3JuYV9ybmEpKSx4ZW5kX2Fycm93PXJlcCgxLjk4LG5yb3coZXBpX2Fycm93X3JuYV9ybmEpKSkNCg0KDQp5PU5VTEwNCg0KZm9yIChpIGluIGVwaV9hcnJvd19ybmFfcm5hWywic291cmNlX25vZGUiXSl7DQogIA0KICB5PWMoeSxtb2R1bGVfdHJhbnNjcmlwdHNfZXBpX2Q2X2Nvb3JkJHlfc291cmNlW21vZHVsZV90cmFuc2NyaXB0c19lcGlfZDZfY29vcmQkc291cmNlX25vZGU9PWldKSAgDQogIA0KfQ0KDQp5ZW5kPU5VTEwNCg0KZm9yIChpIGluIGVwaV9hcnJvd19ybmFfcm5hWywidGFyZ2V0X25vZGUiXSl7DQogIA0KICB5ZW5kPWMoeWVuZCxtb2R1bGVfdHJhbnNjcmlwdHNfZXBpX2Q2X2Nvb3JkJHlfc291cmNlW21vZHVsZV90cmFuc2NyaXB0c19lcGlfZDZfY29vcmQkc291cmNlX25vZGU9PWldKSAgDQogIA0KfQ0KDQplcGlfYXJyb3dfcm5hX3JuYT1jYmluZChlcGlfYXJyb3dfcm5hX3JuYSx5X2Fycm93PXkseWVuZF9hcnJvdz15ZW5kKQ0KDQoNCmVwaV9hcnJvd19ybmFfZG5hPWVwaV9kNl9pbnRlcmFjdGlvbl9kZltlcGlfZDZfaW50ZXJhY3Rpb25fZGZbLCJzb3VyY2Vfbm9kZSJdJWluJW1vZHVsZV90cmFuc2NyaXB0c19lcGlfZDYgJiBlcGlfZDZfaW50ZXJhY3Rpb25fZGZbLCJ0YXJnZXRfbm9kZSJdJWluJW1vZHVsZV9wcm9tb3RlcnNfZXBpX2Q2LF0NCmVwaV9hcnJvd19ybmFfZG5hPWNiaW5kKGVwaV9hcnJvd19ybmFfZG5hLHhfYXJyb3c9cmVwKDEuOTgsbnJvdyhlcGlfYXJyb3dfcm5hX2RuYSkpLHhlbmRfYXJyb3c9cmVwKDEuMTMsbnJvdyhlcGlfYXJyb3dfcm5hX2RuYSkpKQ0KDQoNCnk9TlVMTA0KDQpmb3IgKGkgaW4gZXBpX2Fycm93X3JuYV9kbmFbLCJzb3VyY2Vfbm9kZSJdKXsNCiAgDQogIHk9Yyh5LG1vZHVsZV90cmFuc2NyaXB0c19lcGlfZDZfY29vcmQkeV9zb3VyY2VbbW9kdWxlX3RyYW5zY3JpcHRzX2VwaV9kNl9jb29yZCRzb3VyY2Vfbm9kZT09aV0pICANCiAgDQp9DQoNCnllbmQ9TlVMTA0KDQpmb3IgKGkgaW4gZXBpX2Fycm93X3JuYV9kbmFbLCJ0YXJnZXRfbm9kZSJdKXsNCiAgDQogIHllbmQ9Yyh5ZW5kLG1vZHVsZV9wcm9tb3RlcnNfZXBpX2Q2X2Nvb3JkJHlfc291cmNlW21vZHVsZV9wcm9tb3RlcnNfZXBpX2Q2X2Nvb3JkJHNvdXJjZV9ub2RlPT1pXSkgIA0KICANCn0NCg0KZXBpX2Fycm93X3JuYV9kbmE9Y2JpbmQoZXBpX2Fycm93X3JuYV9kbmEseV9hcnJvdz15LHllbmRfYXJyb3c9eWVuZCkNCg0KDQplcGlfaW50ZXJhY3Rpb25fYXJyb3dzPXJiaW5kKGVwaV9hcnJvd19kbmFfZG5hLGVwaV9hcnJvd19kbmFfcm5hLGVwaV9hcnJvd19ybmFfcm5hLGVwaV9hcnJvd19ybmFfZG5hKQ0KDQplcGlfbW9kdWxlc19jb29yZCRtb2R1bGU9aWZlbHNlKGVwaV9tb2R1bGVzX2Nvb3JkJHhfc291cmNlPT0xLCJkbmEiLCJybmEiKQ0KZXBpX2ludGVyYWN0aW9uX2Fycm93cz1jYmluZChlcGlfaW50ZXJhY3Rpb25fYXJyb3dzLG1vZHVsZV9vcmlnaW49aWZlbHNlKGVwaV9pbnRlcmFjdGlvbl9hcnJvd3NbLCJ4X2Fycm93Il09PTEuMTMsImRuYSIsInJuYSIpKQ0KDQplcGlfbW9kdWxlc19pbnRlcmFjdGlvbl9wbG90PWdncGxvdChlcGlfbW9kdWxlc19jb29yZCxhZXMoeD14X3NvdXJjZSwgeT15X3NvdXJjZSwgbGFiZWw9c291cmNlX25vZGUpKSsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1zb3VyY2Vfbm9kZSwgY29sb3I9YXMuY2hhcmFjdGVyKG1vZHVsZSkpLGhqdXN0PTAsdmp1c3Q9MCkrDQogIGdlb21fcG9pbnQoYWVzKHggPSBpZmVsc2UoeF9zb3VyY2U9PTEsMS4xMywxLjk4KSx5PXlfc291cmNlLCBjb2xvcj1hcy5jaGFyYWN0ZXIobW9kdWxlKSkpKw0KICBnZW9tX2N1cnZlKGRhdGE9YXMuZGF0YS5mcmFtZShlcGlfaW50ZXJhY3Rpb25fYXJyb3dzKSxtYXBwaW5nPWFlcyh4PWFzLm51bWVyaWMoZXBpX2ludGVyYWN0aW9uX2Fycm93c1ssInhfYXJyb3ciXSkseT1hcy5udW1lcmljKGVwaV9pbnRlcmFjdGlvbl9hcnJvd3NbLCJ5X2Fycm93Il0pLHhlbmQ9YXMubnVtZXJpYyhlcGlfaW50ZXJhY3Rpb25fYXJyb3dzWywieGVuZF9hcnJvdyJdKSx5ZW5kPWFzLm51bWVyaWMoZXBpX2ludGVyYWN0aW9uX2Fycm93c1ssInllbmRfYXJyb3ciXSksY29sb3I9YXMuY2hhcmFjdGVyKGVwaV9pbnRlcmFjdGlvbl9hcnJvd3NbLCJtb2R1bGVfb3JpZ2luIl0pKSwgY3VydmF0dXJlID0gLTAuMiwgYXJyb3c9YXJyb3coKSwgc2l6ZT0xKSsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMTNkMzcwIiwicHVycGxlIikpDQoNCg0KDQptb2R1bGVfcHJvbW90ZXJzX3BlX2Q4X2Nvb3JkPU5VTEwNCm1vZHVsZV9wcm9tb3RlcnNfcGVfZDhfY29vcmQkc291cmNlX25vZGU9bW9kdWxlX3Byb21vdGVyc19wZV9kOA0KbW9kdWxlX3Byb21vdGVyc19wZV9kOF9jb29yZCR4X3NvdXJjZT1yZXAoMSxsZW5ndGgobW9kdWxlX3Byb21vdGVyc19wZV9kOCkpDQptb2R1bGVfcHJvbW90ZXJzX3BlX2Q4X2Nvb3JkJHlfc291cmNlPXNlcSh0bz0oMTAwL2xlbmd0aChtb2R1bGVfcHJvbW90ZXJzX3BlX2Q4KSksIGZyb209MTAwLCBieT0tKDEwMC9sZW5ndGgobW9kdWxlX3Byb21vdGVyc19wZV9kOCkpKQ0KbW9kdWxlX3Byb21vdGVyc19wZV9kOF9jb29yZD1hcy5kYXRhLmZyYW1lKG1vZHVsZV9wcm9tb3RlcnNfcGVfZDhfY29vcmQsY29sLm5hbWVzPW5hbWVzKG1vZHVsZV9wcm9tb3RlcnNfcGVfZDhfY29vcmQpKQ0KDQptb2R1bGVfdHJhbnNjcmlwdHNfcGVfZDhfY29vcmQ9TlVMTA0KbW9kdWxlX3RyYW5zY3JpcHRzX3BlX2Q4X2Nvb3JkJHNvdXJjZV9ub2RlPW1vZHVsZV90cmFuc2NyaXB0c19wZV9kOA0KbW9kdWxlX3RyYW5zY3JpcHRzX3BlX2Q4X2Nvb3JkJHhfc291cmNlPXJlcCgyLGxlbmd0aChtb2R1bGVfdHJhbnNjcmlwdHNfcGVfZDgpKQ0KbW9kdWxlX3RyYW5zY3JpcHRzX3BlX2Q4X2Nvb3JkJHlfc291cmNlPXNlcSh0bz0oMTAwL2xlbmd0aChtb2R1bGVfdHJhbnNjcmlwdHNfcGVfZDgpKSwgZnJvbT0xMDAsIGJ5PS0oMTAwL2xlbmd0aChtb2R1bGVfdHJhbnNjcmlwdHNfcGVfZDgpKSkNCm1vZHVsZV90cmFuc2NyaXB0c19wZV9kOF9jb29yZD1hcy5kYXRhLmZyYW1lKG1vZHVsZV90cmFuc2NyaXB0c19wZV9kOF9jb29yZCxjb2wubmFtZXM9bmFtZXMobW9kdWxlX3RyYW5zY3JpcHRzX3BlX2Q4X2Nvb3JkKSkNCg0KcGVfbW9kdWxlc19jb29yZD1yYmluZChtb2R1bGVfcHJvbW90ZXJzX3BlX2Q4X2Nvb3JkLG1vZHVsZV90cmFuc2NyaXB0c19wZV9kOF9jb29yZCkNCg0KcGVfZDhfbW9kdWxlX2Fycm93cz1OVUxMDQoNCiAgDQpwZV9hcnJvd19kbmFfZG5hPXBlX2Q4X2ludGVyYWN0aW9uX2RmW3BlX2Q4X2ludGVyYWN0aW9uX2RmWywic291cmNlX25vZGUiXSVpbiVtb2R1bGVfcHJvbW90ZXJzX3BlX2Q4ICYgcGVfZDhfaW50ZXJhY3Rpb25fZGZbLCJ0YXJnZXRfbm9kZSJdJWluJW1vZHVsZV9wcm9tb3RlcnNfcGVfZDgsXQ0KcGVfYXJyb3dfZG5hX2RuYT1jYmluZChwZV9hcnJvd19kbmFfZG5hLHhfYXJyb3c9cmVwKDEuMTMsbnJvdyhwZV9hcnJvd19kbmFfZG5hKSkseGVuZF9hcnJvdz1yZXAoMS4xMyxucm93KHBlX2Fycm93X2RuYV9kbmEpKSkNCg0KeT1OVUxMDQoNCmZvciAoaSBpbiBwZV9hcnJvd19kbmFfZG5hWywic291cmNlX25vZGUiXSl7DQogIA0KICB5PWMoeSxtb2R1bGVfcHJvbW90ZXJzX3BlX2Q4X2Nvb3JkJHlfc291cmNlW21vZHVsZV9wcm9tb3RlcnNfcGVfZDhfY29vcmQkc291cmNlX25vZGU9PWldKSAgDQogIA0KfQ0KDQp5ZW5kPU5VTEwNCg0KZm9yIChpIGluIHBlX2Fycm93X2RuYV9kbmFbLCJ0YXJnZXRfbm9kZSJdKXsNCiAgDQogIHllbmQ9Yyh5ZW5kLG1vZHVsZV9wcm9tb3RlcnNfcGVfZDhfY29vcmQkeV9zb3VyY2VbbW9kdWxlX3Byb21vdGVyc19wZV9kOF9jb29yZCRzb3VyY2Vfbm9kZT09aV0pICANCiAgDQp9DQoNCnBlX2Fycm93X2RuYV9kbmE9Y2JpbmQocGVfYXJyb3dfZG5hX2RuYSx5X2Fycm93PXkseWVuZF9hcnJvdz15ZW5kKQ0KDQpwZV9hcnJvd19kbmFfcm5hPXBlX2Q4X2ludGVyYWN0aW9uX2RmW3BlX2Q4X2ludGVyYWN0aW9uX2RmWywic291cmNlX25vZGUiXSVpbiVtb2R1bGVfcHJvbW90ZXJzX3BlX2Q4ICYgcGVfZDhfaW50ZXJhY3Rpb25fZGZbLCJ0YXJnZXRfbm9kZSJdJWluJW1vZHVsZV90cmFuc2NyaXB0c19wZV9kOCxdDQpwZV9hcnJvd19kbmFfcm5hPWNiaW5kKHBlX2Fycm93X2RuYV9ybmEseF9hcnJvdz1yZXAoMS4xMyxucm93KHBlX2Fycm93X2RuYV9ybmEpKSx4ZW5kX2Fycm93PXJlcCgxLjk4LG5yb3cocGVfYXJyb3dfZG5hX3JuYSkpKQ0KDQp5PU5VTEwNCg0KZm9yIChpIGluIHBlX2Fycm93X2RuYV9ybmFbLCJzb3VyY2Vfbm9kZSJdKXsNCiAgDQogIHk9Yyh5LG1vZHVsZV9wcm9tb3RlcnNfcGVfZDhfY29vcmQkeV9zb3VyY2VbbW9kdWxlX3Byb21vdGVyc19wZV9kOF9jb29yZCRzb3VyY2Vfbm9kZT09aV0pICANCiAgDQp9DQoNCnllbmQ9TlVMTA0KDQpmb3IgKGkgaW4gcGVfYXJyb3dfZG5hX3JuYVssInRhcmdldF9ub2RlIl0pew0KICANCiAgeWVuZD1jKHllbmQsbW9kdWxlX3RyYW5zY3JpcHRzX3BlX2Q4X2Nvb3JkJHlfc291cmNlW21vZHVsZV90cmFuc2NyaXB0c19wZV9kOF9jb29yZCRzb3VyY2Vfbm9kZT09aV0pICANCiAgDQp9DQoNCnBlX2Fycm93X2RuYV9ybmE9Y2JpbmQocGVfYXJyb3dfZG5hX3JuYSx5X2Fycm93PXkseWVuZF9hcnJvdz15ZW5kKQ0KDQpwZV9hcnJvd19ybmFfcm5hPXBlX2Q4X2ludGVyYWN0aW9uX2RmW3BlX2Q4X2ludGVyYWN0aW9uX2RmWywic291cmNlX25vZGUiXSVpbiVtb2R1bGVfdHJhbnNjcmlwdHNfcGVfZDggJiBwZV9kOF9pbnRlcmFjdGlvbl9kZlssInRhcmdldF9ub2RlIl0laW4lbW9kdWxlX3RyYW5zY3JpcHRzX3BlX2Q4LF0NCnBlX2Fycm93X3JuYV9ybmE9Y2JpbmQocGVfYXJyb3dfcm5hX3JuYSx4X2Fycm93PXJlcCgxLjk4LG5yb3cocGVfYXJyb3dfcm5hX3JuYSkpLHhlbmRfYXJyb3c9cmVwKDEuOTgsbnJvdyhwZV9hcnJvd19ybmFfcm5hKSkpDQoNCg0KeT1OVUxMDQoNCmZvciAoaSBpbiBwZV9hcnJvd19ybmFfcm5hWywic291cmNlX25vZGUiXSl7DQogIA0KICB5PWMoeSxtb2R1bGVfdHJhbnNjcmlwdHNfcGVfZDhfY29vcmQkeV9zb3VyY2VbbW9kdWxlX3RyYW5zY3JpcHRzX3BlX2Q4X2Nvb3JkJHNvdXJjZV9ub2RlPT1pXSkgIA0KICANCn0NCg0KeWVuZD1OVUxMDQoNCmZvciAoaSBpbiBwZV9hcnJvd19ybmFfcm5hWywidGFyZ2V0X25vZGUiXSl7DQogIA0KICB5ZW5kPWMoeWVuZCxtb2R1bGVfdHJhbnNjcmlwdHNfcGVfZDhfY29vcmQkeV9zb3VyY2VbbW9kdWxlX3RyYW5zY3JpcHRzX3BlX2Q4X2Nvb3JkJHNvdXJjZV9ub2RlPT1pXSkgIA0KICANCn0NCg0KcGVfYXJyb3dfcm5hX3JuYT1jYmluZChwZV9hcnJvd19ybmFfcm5hLHlfYXJyb3c9eSx5ZW5kX2Fycm93PXllbmQpDQoNCg0KcGVfYXJyb3dfcm5hX2RuYT1wZV9kOF9pbnRlcmFjdGlvbl9kZltwZV9kOF9pbnRlcmFjdGlvbl9kZlssInNvdXJjZV9ub2RlIl0laW4lbW9kdWxlX3RyYW5zY3JpcHRzX3BlX2Q4ICYgcGVfZDhfaW50ZXJhY3Rpb25fZGZbLCJ0YXJnZXRfbm9kZSJdJWluJW1vZHVsZV9wcm9tb3RlcnNfcGVfZDgsXQ0KcGVfYXJyb3dfcm5hX2RuYT1jYmluZChwZV9hcnJvd19ybmFfZG5hLHhfYXJyb3c9cmVwKDEuOTgsbnJvdyhwZV9hcnJvd19ybmFfZG5hKSkseGVuZF9hcnJvdz1yZXAoMS4xMyxucm93KHBlX2Fycm93X3JuYV9kbmEpKSkNCg0KDQp5PU5VTEwNCg0KZm9yIChpIGluIHBlX2Fycm93X3JuYV9kbmFbLCJzb3VyY2Vfbm9kZSJdKXsNCiAgDQogIHk9Yyh5LG1vZHVsZV90cmFuc2NyaXB0c19wZV9kOF9jb29yZCR5X3NvdXJjZVttb2R1bGVfdHJhbnNjcmlwdHNfcGVfZDhfY29vcmQkc291cmNlX25vZGU9PWldKSAgDQogIA0KfQ0KDQp5ZW5kPU5VTEwNCg0KZm9yIChpIGluIHBlX2Fycm93X3JuYV9kbmFbLCJ0YXJnZXRfbm9kZSJdKXsNCiAgDQogIHllbmQ9Yyh5ZW5kLG1vZHVsZV9wcm9tb3RlcnNfcGVfZDhfY29vcmQkeV9zb3VyY2VbbW9kdWxlX3Byb21vdGVyc19wZV9kOF9jb29yZCRzb3VyY2Vfbm9kZT09aV0pICANCiAgDQp9DQoNCnBlX2Fycm93X3JuYV9kbmE9Y2JpbmQocGVfYXJyb3dfcm5hX2RuYSx5X2Fycm93PXkseWVuZF9hcnJvdz15ZW5kKQ0KDQoNCnBlX2ludGVyYWN0aW9uX2Fycm93cz1yYmluZChwZV9hcnJvd19kbmFfZG5hLHBlX2Fycm93X2RuYV9ybmEscGVfYXJyb3dfcm5hX3JuYSxwZV9hcnJvd19ybmFfZG5hKQ0KDQoNCnBlX21vZHVsZXNfY29vcmQkbW9kdWxlPWlmZWxzZShwZV9tb2R1bGVzX2Nvb3JkJHhfc291cmNlPT0xLCJkbmEiLCJybmEiKQ0KcGVfaW50ZXJhY3Rpb25fYXJyb3dzPWNiaW5kKHBlX2ludGVyYWN0aW9uX2Fycm93cyxtb2R1bGVfb3JpZ2luPWlmZWxzZShwZV9pbnRlcmFjdGlvbl9hcnJvd3NbLCJ4X2Fycm93Il09PTEuMTMsImRuYSIsInJuYSIpKQ0KDQpwZV9tb2R1bGVzX2ludGVyYWN0aW9uX3Bsb3Q9Z2dwbG90KHBlX21vZHVsZXNfY29vcmQsYWVzKHg9eF9zb3VyY2UsIHk9eV9zb3VyY2UsIGxhYmVsPXNvdXJjZV9ub2RlKSkrDQogIGdlb21fdGV4dChhZXMobGFiZWw9c291cmNlX25vZGUsIGNvbG9yPWFzLmNoYXJhY3Rlcihtb2R1bGUpKSxoanVzdD0wLHZqdXN0PTApKw0KICBnZW9tX3BvaW50KGFlcyh4ID0gaWZlbHNlKHhfc291cmNlPT0xLDEuMTMsMS45OCkseT15X3NvdXJjZSwgY29sb3I9YXMuY2hhcmFjdGVyKG1vZHVsZSkpKSsNCiAgZ2VvbV9jdXJ2ZShkYXRhPWFzLmRhdGEuZnJhbWUocGVfaW50ZXJhY3Rpb25fYXJyb3dzKSxtYXBwaW5nPWFlcyh4PWFzLm51bWVyaWMocGVfaW50ZXJhY3Rpb25fYXJyb3dzWywieF9hcnJvdyJdKSx5PWFzLm51bWVyaWMocGVfaW50ZXJhY3Rpb25fYXJyb3dzWywieV9hcnJvdyJdKSx4ZW5kPWFzLm51bWVyaWMocGVfaW50ZXJhY3Rpb25fYXJyb3dzWywieGVuZF9hcnJvdyJdKSx5ZW5kPWFzLm51bWVyaWMocGVfaW50ZXJhY3Rpb25fYXJyb3dzWywieWVuZF9hcnJvdyJdKSxjb2xvcj1hcy5jaGFyYWN0ZXIocGVfaW50ZXJhY3Rpb25fYXJyb3dzWywibW9kdWxlX29yaWdpbiJdKSksIGN1cnZhdHVyZSA9IC0wLjIsIGFycm93PWFycm93KCksIHNpemU9MSkrDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzEzZDM3MCIsInB1cnBsZSIpKQ0KDQoNCg0KDQoNCm1vZHVsZV9wcm9tb3RlcnNfdGVfZDZfY29vcmQ9TlVMTA0KbW9kdWxlX3Byb21vdGVyc190ZV9kNl9jb29yZCRzb3VyY2Vfbm9kZT1tb2R1bGVfcHJvbW90ZXJzX3RlX2Q2DQptb2R1bGVfcHJvbW90ZXJzX3RlX2Q2X2Nvb3JkJHhfc291cmNlPXJlcCgxLGxlbmd0aChtb2R1bGVfcHJvbW90ZXJzX3RlX2Q2KSkNCm1vZHVsZV9wcm9tb3RlcnNfdGVfZDZfY29vcmQkeV9zb3VyY2U9c2VxKHRvPSgxMDAvbGVuZ3RoKG1vZHVsZV9wcm9tb3RlcnNfdGVfZDYpKSwgZnJvbT0xMDAsIGJ5PS0oMTAwL2xlbmd0aChtb2R1bGVfcHJvbW90ZXJzX3RlX2Q2KSkpDQptb2R1bGVfcHJvbW90ZXJzX3RlX2Q2X2Nvb3JkPWFzLmRhdGEuZnJhbWUobW9kdWxlX3Byb21vdGVyc190ZV9kNl9jb29yZCxjb2wubmFtZXM9bmFtZXMobW9kdWxlX3Byb21vdGVyc190ZV9kNl9jb29yZCkpDQoNCm1vZHVsZV90cmFuc2NyaXB0c190ZV9kNl9jb29yZD1OVUxMDQptb2R1bGVfdHJhbnNjcmlwdHNfdGVfZDZfY29vcmQkc291cmNlX25vZGU9bW9kdWxlX3RyYW5zY3JpcHRzX3RlX2Q2DQptb2R1bGVfdHJhbnNjcmlwdHNfdGVfZDZfY29vcmQkeF9zb3VyY2U9cmVwKDIsbGVuZ3RoKG1vZHVsZV90cmFuc2NyaXB0c190ZV9kNikpDQptb2R1bGVfdHJhbnNjcmlwdHNfdGVfZDZfY29vcmQkeV9zb3VyY2U9c2VxKHRvPSgxMDAvbGVuZ3RoKG1vZHVsZV90cmFuc2NyaXB0c190ZV9kNikpLCBmcm9tPTEwMCwgYnk9LSgxMDAvbGVuZ3RoKG1vZHVsZV90cmFuc2NyaXB0c190ZV9kNikpKQ0KbW9kdWxlX3RyYW5zY3JpcHRzX3RlX2Q2X2Nvb3JkPWFzLmRhdGEuZnJhbWUobW9kdWxlX3RyYW5zY3JpcHRzX3RlX2Q2X2Nvb3JkLGNvbC5uYW1lcz1uYW1lcyhtb2R1bGVfdHJhbnNjcmlwdHNfdGVfZDZfY29vcmQpKQ0KDQp0ZV9tb2R1bGVzX2Nvb3JkPXJiaW5kKG1vZHVsZV9wcm9tb3RlcnNfdGVfZDZfY29vcmQsbW9kdWxlX3RyYW5zY3JpcHRzX3RlX2Q2X2Nvb3JkKQ0KDQp0ZV9kNl9tb2R1bGVfYXJyb3dzPU5VTEwNCg0KICANCnRlX2Fycm93X2RuYV9kbmE9dGVfZDZfaW50ZXJhY3Rpb25fZGZbdGVfZDZfaW50ZXJhY3Rpb25fZGZbLCJzb3VyY2Vfbm9kZSJdJWluJW1vZHVsZV9wcm9tb3RlcnNfdGVfZDYgJiB0ZV9kNl9pbnRlcmFjdGlvbl9kZlssInRhcmdldF9ub2RlIl0laW4lbW9kdWxlX3Byb21vdGVyc190ZV9kNixdDQp0ZV9hcnJvd19kbmFfZG5hPWNiaW5kKHRlX2Fycm93X2RuYV9kbmEseF9hcnJvdz1yZXAoMS4xMyxucm93KHRlX2Fycm93X2RuYV9kbmEpKSx4ZW5kX2Fycm93PXJlcCgxLjEzLG5yb3codGVfYXJyb3dfZG5hX2RuYSkpKQ0KDQp5PU5VTEwNCg0KZm9yIChpIGluIHRlX2Fycm93X2RuYV9kbmFbLCJzb3VyY2Vfbm9kZSJdKXsNCiAgDQogIHk9Yyh5LG1vZHVsZV9wcm9tb3RlcnNfdGVfZDZfY29vcmQkeV9zb3VyY2VbbW9kdWxlX3Byb21vdGVyc190ZV9kNl9jb29yZCRzb3VyY2Vfbm9kZT09aV0pICANCiAgDQp9DQoNCnllbmQ9TlVMTA0KDQpmb3IgKGkgaW4gdGVfYXJyb3dfZG5hX2RuYVssInRhcmdldF9ub2RlIl0pew0KICANCiAgeWVuZD1jKHllbmQsbW9kdWxlX3Byb21vdGVyc190ZV9kNl9jb29yZCR5X3NvdXJjZVttb2R1bGVfcHJvbW90ZXJzX3RlX2Q2X2Nvb3JkJHNvdXJjZV9ub2RlPT1pXSkgIA0KICANCn0NCg0KdGVfYXJyb3dfZG5hX2RuYT1jYmluZCh0ZV9hcnJvd19kbmFfZG5hLHlfYXJyb3c9eSx5ZW5kX2Fycm93PXllbmQpDQoNCnRlX2Fycm93X2RuYV9ybmE9dGVfZDZfaW50ZXJhY3Rpb25fZGZbdGVfZDZfaW50ZXJhY3Rpb25fZGZbLCJzb3VyY2Vfbm9kZSJdJWluJW1vZHVsZV9wcm9tb3RlcnNfdGVfZDYgJiB0ZV9kNl9pbnRlcmFjdGlvbl9kZlssInRhcmdldF9ub2RlIl0laW4lbW9kdWxlX3RyYW5zY3JpcHRzX3RlX2Q2LF0NCnRlX2Fycm93X2RuYV9ybmE9Y2JpbmQodGVfYXJyb3dfZG5hX3JuYSx4X2Fycm93PXJlcCgxLjEzLG5yb3codGVfYXJyb3dfZG5hX3JuYSkpLHhlbmRfYXJyb3c9cmVwKDEuOTgsbnJvdyh0ZV9hcnJvd19kbmFfcm5hKSkpDQoNCnk9TlVMTA0KDQpmb3IgKGkgaW4gdGVfYXJyb3dfZG5hX3JuYVssInNvdXJjZV9ub2RlIl0pew0KICANCiAgeT1jKHksbW9kdWxlX3Byb21vdGVyc190ZV9kNl9jb29yZCR5X3NvdXJjZVttb2R1bGVfcHJvbW90ZXJzX3RlX2Q2X2Nvb3JkJHNvdXJjZV9ub2RlPT1pXSkgIA0KICANCn0NCg0KeWVuZD1OVUxMDQoNCmZvciAoaSBpbiB0ZV9hcnJvd19kbmFfcm5hWywidGFyZ2V0X25vZGUiXSl7DQogIA0KICB5ZW5kPWMoeWVuZCxtb2R1bGVfdHJhbnNjcmlwdHNfdGVfZDZfY29vcmQkeV9zb3VyY2VbbW9kdWxlX3RyYW5zY3JpcHRzX3RlX2Q2X2Nvb3JkJHNvdXJjZV9ub2RlPT1pXSkgIA0KICANCn0NCg0KdGVfYXJyb3dfZG5hX3JuYT1jYmluZCh0ZV9hcnJvd19kbmFfcm5hLHlfYXJyb3c9eSx5ZW5kX2Fycm93PXllbmQpDQoNCnRlX2Fycm93X3JuYV9ybmE9dGVfZDZfaW50ZXJhY3Rpb25fZGZbdGVfZDZfaW50ZXJhY3Rpb25fZGZbLCJzb3VyY2Vfbm9kZSJdJWluJW1vZHVsZV90cmFuc2NyaXB0c190ZV9kNiAmIHRlX2Q2X2ludGVyYWN0aW9uX2RmWywidGFyZ2V0X25vZGUiXSVpbiVtb2R1bGVfdHJhbnNjcmlwdHNfdGVfZDYsXQ0KdGVfYXJyb3dfcm5hX3JuYT1jYmluZCh0ZV9hcnJvd19ybmFfcm5hLHhfYXJyb3c9cmVwKDEuOTgsbnJvdyh0ZV9hcnJvd19ybmFfcm5hKSkseGVuZF9hcnJvdz1yZXAoMS45OCxucm93KHRlX2Fycm93X3JuYV9ybmEpKSkNCg0KDQp5PU5VTEwNCg0KZm9yIChpIGluIHRlX2Fycm93X3JuYV9ybmFbLCJzb3VyY2Vfbm9kZSJdKXsNCiAgDQogIHk9Yyh5LG1vZHVsZV90cmFuc2NyaXB0c190ZV9kNl9jb29yZCR5X3NvdXJjZVttb2R1bGVfdHJhbnNjcmlwdHNfdGVfZDZfY29vcmQkc291cmNlX25vZGU9PWldKSAgDQogIA0KfQ0KDQp5ZW5kPU5VTEwNCg0KZm9yIChpIGluIHRlX2Fycm93X3JuYV9ybmFbLCJ0YXJnZXRfbm9kZSJdKXsNCiAgDQogIHllbmQ9Yyh5ZW5kLG1vZHVsZV90cmFuc2NyaXB0c190ZV9kNl9jb29yZCR5X3NvdXJjZVttb2R1bGVfdHJhbnNjcmlwdHNfdGVfZDZfY29vcmQkc291cmNlX25vZGU9PWldKSAgDQogIA0KfQ0KDQp0ZV9hcnJvd19ybmFfcm5hPWNiaW5kKHRlX2Fycm93X3JuYV9ybmEseV9hcnJvdz15LHllbmRfYXJyb3c9eWVuZCkNCg0KDQp0ZV9hcnJvd19ybmFfZG5hPXRlX2Q2X2ludGVyYWN0aW9uX2RmW3RlX2Q2X2ludGVyYWN0aW9uX2RmWywic291cmNlX25vZGUiXSVpbiVtb2R1bGVfdHJhbnNjcmlwdHNfdGVfZDYgJiB0ZV9kNl9pbnRlcmFjdGlvbl9kZlssInRhcmdldF9ub2RlIl0laW4lbW9kdWxlX3Byb21vdGVyc190ZV9kNixdDQp0ZV9hcnJvd19ybmFfZG5hPWNiaW5kKHRlX2Fycm93X3JuYV9kbmEseF9hcnJvdz1yZXAoMS45OCxucm93KHRlX2Fycm93X3JuYV9kbmEpKSx4ZW5kX2Fycm93PXJlcCgxLjEzLG5yb3codGVfYXJyb3dfcm5hX2RuYSkpKQ0KDQoNCnk9TlVMTA0KDQpmb3IgKGkgaW4gdGVfYXJyb3dfcm5hX2RuYVssInNvdXJjZV9ub2RlIl0pew0KICANCiAgeT1jKHksbW9kdWxlX3RyYW5zY3JpcHRzX3RlX2Q2X2Nvb3JkJHlfc291cmNlW21vZHVsZV90cmFuc2NyaXB0c190ZV9kNl9jb29yZCRzb3VyY2Vfbm9kZT09aV0pICANCiAgDQp9DQoNCnllbmQ9TlVMTA0KDQpmb3IgKGkgaW4gdGVfYXJyb3dfcm5hX2RuYVssInRhcmdldF9ub2RlIl0pew0KICANCiAgeWVuZD1jKHllbmQsbW9kdWxlX3Byb21vdGVyc190ZV9kNl9jb29yZCR5X3NvdXJjZVttb2R1bGVfcHJvbW90ZXJzX3RlX2Q2X2Nvb3JkJHNvdXJjZV9ub2RlPT1pXSkgIA0KICANCn0NCg0KdGVfYXJyb3dfcm5hX2RuYT1jYmluZCh0ZV9hcnJvd19ybmFfZG5hLHlfYXJyb3c9eSx5ZW5kX2Fycm93PXllbmQpDQoNCg0KdGVfaW50ZXJhY3Rpb25fYXJyb3dzPXJiaW5kKHRlX2Fycm93X2RuYV9kbmEsdGVfYXJyb3dfZG5hX3JuYSx0ZV9hcnJvd19ybmFfcm5hLHRlX2Fycm93X3JuYV9kbmEpDQoNCg0KdGVfbW9kdWxlc19jb29yZCRtb2R1bGU9aWZlbHNlKHRlX21vZHVsZXNfY29vcmQkeF9zb3VyY2U9PTEsImRuYSIsInJuYSIpDQp0ZV9pbnRlcmFjdGlvbl9hcnJvd3M9Y2JpbmQodGVfaW50ZXJhY3Rpb25fYXJyb3dzLG1vZHVsZV9vcmlnaW49aWZlbHNlKHRlX2ludGVyYWN0aW9uX2Fycm93c1ssInhfYXJyb3ciXT09MS4xMywiZG5hIiwicm5hIikpDQoNCnRlX21vZHVsZXNfaW50ZXJhY3Rpb25fcGxvdD1nZ3Bsb3QodGVfbW9kdWxlc19jb29yZCxhZXMoeD14X3NvdXJjZSwgeT15X3NvdXJjZSwgbGFiZWw9c291cmNlX25vZGUpKSsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1zb3VyY2Vfbm9kZSwgY29sb3I9YXMuY2hhcmFjdGVyKG1vZHVsZSkpLGhqdXN0PTAsdmp1c3Q9MCkrDQogIGdlb21fcG9pbnQoYWVzKHggPSBpZmVsc2UoeF9zb3VyY2U9PTEsMS4xMywxLjk4KSx5PXlfc291cmNlLCBjb2xvcj1hcy5jaGFyYWN0ZXIobW9kdWxlKSkpKw0KICBnZW9tX2N1cnZlKGRhdGE9YXMuZGF0YS5mcmFtZSh0ZV9pbnRlcmFjdGlvbl9hcnJvd3MpLG1hcHBpbmc9YWVzKHg9YXMubnVtZXJpYyh0ZV9pbnRlcmFjdGlvbl9hcnJvd3NbLCJ4X2Fycm93Il0pLHk9YXMubnVtZXJpYyh0ZV9pbnRlcmFjdGlvbl9hcnJvd3NbLCJ5X2Fycm93Il0pLHhlbmQ9YXMubnVtZXJpYyh0ZV9pbnRlcmFjdGlvbl9hcnJvd3NbLCJ4ZW5kX2Fycm93Il0pLHllbmQ9YXMubnVtZXJpYyh0ZV9pbnRlcmFjdGlvbl9hcnJvd3NbLCJ5ZW5kX2Fycm93Il0pLGNvbG9yPWFzLmNoYXJhY3Rlcih0ZV9pbnRlcmFjdGlvbl9hcnJvd3NbLCJtb2R1bGVfb3JpZ2luIl0pKSwgY3VydmF0dXJlID0gLTAuMiwgYXJyb3c9YXJyb3coKSwgc2l6ZT0xKSsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMTNkMzcwIiwicHVycGxlIikpDQoNCg0KDQoNCmVwaV9kNl9kbmFfc2l6ZSA9IE5VTEwNCg0KZm9yIChpIGluIG1vZHVsZV9wcm9tb3RlcnNfZXBpX2Q2KXsNCiAgZXBpX2Q2X2RuYV9zaXplPWMoZXBpX2Q2X2RuYV9zaXplLHN1bShlcGlfaW50ZXJhY3Rpb25fYXJyb3dzWywic291cmNlX25vZGUiXT09aSkpDQp9DQpuYW1lcyhlcGlfZDZfZG5hX3NpemUpPW1vZHVsZV9wcm9tb3RlcnNfZXBpX2Q2DQoNCg0KDQplcGlfZDZfcm5hX3NpemUgPSBOVUxMDQoNCmZvciAoaSBpbiBtb2R1bGVfdHJhbnNjcmlwdHNfZXBpX2Q2KXsNCiAgDQogIGVwaV9kNl9ybmFfc2l6ZT1jKGVwaV9kNl9ybmFfc2l6ZSxzdW0oZXBpX2ludGVyYWN0aW9uX2Fycm93c1ssInNvdXJjZV9ub2RlIl09PWkpKQ0KfQ0KbmFtZXMoZXBpX2Q2X3JuYV9zaXplKT1tb2R1bGVfdHJhbnNjcmlwdHNfZXBpX2Q2DQoNCg0KcGVfZDhfZG5hX3NpemUgPSBOVUxMDQoNCmZvciAoaSBpbiBtb2R1bGVfcHJvbW90ZXJzX3BlX2Q4KXsNCiAgcGVfZDhfZG5hX3NpemU9YyhwZV9kOF9kbmFfc2l6ZSxzdW0ocGVfaW50ZXJhY3Rpb25fYXJyb3dzWywic291cmNlX25vZGUiXT09aSkpDQp9DQpuYW1lcyhwZV9kOF9kbmFfc2l6ZSk9bW9kdWxlX3Byb21vdGVyc19wZV9kOA0KDQoNCnBlX2Q4X3JuYV9zaXplID0gTlVMTA0KDQpmb3IgKGkgaW4gbW9kdWxlX3RyYW5zY3JpcHRzX3BlX2Q4KXsNCiAgcGVfZDhfcm5hX3NpemU9YyhwZV9kOF9ybmFfc2l6ZSxzdW0ocGVfaW50ZXJhY3Rpb25fYXJyb3dzWywic291cmNlX25vZGUiXT09aSkpDQp9DQpuYW1lcyhwZV9kOF9ybmFfc2l6ZSk9bW9kdWxlX3RyYW5zY3JpcHRzX3BlX2Q4DQoNCg0KdGVfZDZfZG5hX3NpemUgPSBOVUxMDQoNCmZvciAoaSBpbiBtb2R1bGVfcHJvbW90ZXJzX3RlX2Q2KXsNCiAgdGVfZDZfZG5hX3NpemU9Yyh0ZV9kNl9kbmFfc2l6ZSxzdW0odGVfaW50ZXJhY3Rpb25fYXJyb3dzWywic291cmNlX25vZGUiXT09aSkpDQp9DQpuYW1lcyh0ZV9kNl9kbmFfc2l6ZSk9bW9kdWxlX3Byb21vdGVyc190ZV9kNg0KDQoNCnRlX2Q2X3JuYV9zaXplID0gTlVMTA0KDQpmb3IgKGkgaW4gbW9kdWxlX3RyYW5zY3JpcHRzX3RlX2Q2KXsNCiAgdGVfZDZfcm5hX3NpemU9Yyh0ZV9kNl9ybmFfc2l6ZSxzdW0odGVfaW50ZXJhY3Rpb25fYXJyb3dzWywic291cmNlX25vZGUiXT09aSkpDQp9DQpuYW1lcyh0ZV9kNl9ybmFfc2l6ZSk9bW9kdWxlX3RyYW5zY3JpcHRzX3RlX2Q2DQoNCiMgc2F2ZS5pbWFnZSgiMjAyMV8wNl8xNF9uZXR3b3JrLlJEYXRhIikNCmxvYWQoIjIwMjFfMDZfMTRfbmV0d29yay5SRGF0YSIpDQpgYGBgDQoNCg0KYGBgYHtyIGFwcGx5IFBDQSB0byBiaW5hcml6ZWQgbW9kdWxlIGFkamFjZW5jeSBtYXRyaWNlc30NCg0KZXBpX2Q2X2RuYV9tb2R1bGVfYWNwPUFDUChpZmVsc2UoZXBpX2Q2X2RuYV9hZGphY2VuY3lfc2VsZWN0ZWQ+bWVkaWFuKGVwaV9kNl9kbmFfYWRqYWNlbmN5X3NlbGVjdGVkKSwxLDApKQ0KZXBpX2Q2X3JuYV9tb2R1bGVfYWNwPUFDUChpZmVsc2UoZXBpX2Q2X3JuYV9hZGphY2VuY3lfc2VsZWN0ZWQ+bWVkaWFuKGVwaV9kNl9ybmFfYWRqYWNlbmN5X3NlbGVjdGVkKSwxLDApKQ0KDQpwZV9kOF9kbmFfbW9kdWxlX2FjcD1BQ1AoaWZlbHNlKHBlX2Q4X2RuYV9hZGphY2VuY3lfc2VsZWN0ZWQ+bWVkaWFuKHBlX2Q4X2RuYV9hZGphY2VuY3lfc2VsZWN0ZWQpLDEsMCkpDQpwZV9kOF9ybmFfbW9kdWxlX2FjcD1BQ1AoaWZlbHNlKHBlX2Q4X3JuYV9hZGphY2VuY3lfc2VsZWN0ZWQ+bWVkaWFuKHBlX2Q4X3JuYV9hZGphY2VuY3lfc2VsZWN0ZWQpLDEsMCkpDQoNCnRlX2Q2X2RuYV9tb2R1bGVfYWNwPUFDUChpZmVsc2UodGVfZDZfZG5hX2FkamFjZW5jeV9zZWxlY3RlZD5tZWRpYW4odGVfZDZfZG5hX2FkamFjZW5jeV9zZWxlY3RlZCksMSwwKSkNCnRlX2Q2X3JuYV9tb2R1bGVfYWNwPUFDUChpZmVsc2UodGVfZDZfcm5hX2FkamFjZW5jeV9zZWxlY3RlZD5tZWRpYW4odGVfZDZfcm5hX2FkamFjZW5jeV9zZWxlY3RlZCksMSwwKSkNCg0KYGBgYA0KDQoNCmBgYGB7ciBidWlsZGluZyAzRCBhcnJvd3N9DQoNCmVwaV9kNl9tb2R1bGVfM2RfYXJyb3dzPU5VTEwNCg0KICANCmVwaV8zZF9hcnJvd19kbmFfZG5hPWVwaV9kNl9pbnRlcmFjdGlvbl9kZltlcGlfZDZfaW50ZXJhY3Rpb25fZGZbLCJzb3VyY2Vfbm9kZSJdJWluJW1vZHVsZV9wcm9tb3RlcnNfZXBpX2Q2ICYgZXBpX2Q2X2ludGVyYWN0aW9uX2RmWywidGFyZ2V0X25vZGUiXSVpbiVtb2R1bGVfcHJvbW90ZXJzX2VwaV9kNixjKCJzb3VyY2Vfbm9kZSIsInRhcmdldF9ub2RlIildDQoNCnh5ej1OVUxMDQpmb3IgKGkgaW4gZXBpXzNkX2Fycm93X2RuYV9kbmFbLCJzb3VyY2Vfbm9kZSJdKXsNCiAgeHl6PXJiaW5kKHh5eixlcGlfZDZfZG5hX21vZHVsZV9hY3AkeFtyb3duYW1lcyhlcGlfZDZfZG5hX21vZHVsZV9hY3AkeCk9PWksYygxOjMpXSkgIA0KfQ0KDQoNCg0KeHl6X2VuZD1OVUxMDQpmb3IgKGkgaW4gZXBpXzNkX2Fycm93X2RuYV9kbmFbLCJ0YXJnZXRfbm9kZSJdKXsNCiAgeHl6X2VuZD1yYmluZCh4eXpfZW5kLGVwaV9kNl9kbmFfbW9kdWxlX2FjcCR4W3Jvd25hbWVzKGVwaV9kNl9kbmFfbW9kdWxlX2FjcCR4KT09aSxjKDE6MyldKSAgDQp9DQoNCmVwaV9kbmFfZG5hXzNkX2Fycm93cz1kYXRhLmZyYW1lKGVwaV8zZF9hcnJvd19kbmFfZG5hLHhfM2RfYXJyb3c9eHl6WywxXSx5XzNkX2Fycm93PXh5elssMl0sIHpfM2RfYXJyb3c9eHl6WywzXSx4ZW5kXzNkX2Fycm93PXh5el9lbmRbLDFdLHllbmRfM2RfYXJyb3c9eHl6X2VuZFssMl0semVuZF8zZF9hcnJvdz14eXpfZW5kWywzXSkNCg0KDQoNCg0KDQpwZV9kOF9tb2R1bGVfM2RfYXJyb3dzPU5VTEwNCg0KICANCnBlXzNkX2Fycm93X2RuYV9kbmE9cGVfZDhfaW50ZXJhY3Rpb25fZGZbcGVfZDhfaW50ZXJhY3Rpb25fZGZbLCJzb3VyY2Vfbm9kZSJdJWluJW1vZHVsZV9wcm9tb3RlcnNfcGVfZDggJiBwZV9kOF9pbnRlcmFjdGlvbl9kZlssInRhcmdldF9ub2RlIl0laW4lbW9kdWxlX3Byb21vdGVyc19wZV9kOCxjKCJzb3VyY2Vfbm9kZSIsInRhcmdldF9ub2RlIildDQoNCnh5ej1OVUxMDQpmb3IgKGkgaW4gcGVfM2RfYXJyb3dfZG5hX2RuYVssInNvdXJjZV9ub2RlIl0pew0KICB4eXo9cmJpbmQoeHl6LHBlX2Q4X2RuYV9tb2R1bGVfYWNwJHhbcm93bmFtZXMocGVfZDhfZG5hX21vZHVsZV9hY3AkeCk9PWksYygxOjMpXSkgIA0KfQ0KDQoNCg0KeHl6X2VuZD1OVUxMDQpmb3IgKGkgaW4gcGVfM2RfYXJyb3dfZG5hX2RuYVssInRhcmdldF9ub2RlIl0pew0KICB4eXpfZW5kPXJiaW5kKHh5el9lbmQscGVfZDhfZG5hX21vZHVsZV9hY3AkeFtyb3duYW1lcyhwZV9kOF9kbmFfbW9kdWxlX2FjcCR4KT09aSxjKDE6MyldKSAgDQp9DQoNCnBlX2RuYV9kbmFfM2RfYXJyb3dzPWRhdGEuZnJhbWUocGVfM2RfYXJyb3dfZG5hX2RuYSx4XzNkX2Fycm93PXh5elssMV0seV8zZF9hcnJvdz14eXpbLDJdLCB6XzNkX2Fycm93PXh5elssM10seGVuZF8zZF9hcnJvdz14eXpfZW5kWywxXSx5ZW5kXzNkX2Fycm93PXh5el9lbmRbLDJdLHplbmRfM2RfYXJyb3c9eHl6X2VuZFssM10pDQoNCg0KDQoNCg0KdGVfZDZfbW9kdWxlXzNkX2Fycm93cz1OVUxMDQoNCiAgDQp0ZV8zZF9hcnJvd19kbmFfZG5hPXRlX2Q2X2ludGVyYWN0aW9uX2RmW3RlX2Q2X2ludGVyYWN0aW9uX2RmWywic291cmNlX25vZGUiXSVpbiVtb2R1bGVfcHJvbW90ZXJzX3RlX2Q2ICYgdGVfZDZfaW50ZXJhY3Rpb25fZGZbLCJ0YXJnZXRfbm9kZSJdJWluJW1vZHVsZV9wcm9tb3RlcnNfdGVfZDYsYygic291cmNlX25vZGUiLCJ0YXJnZXRfbm9kZSIpXQ0KDQp4eXo9TlVMTA0KZm9yIChpIGluIHRlXzNkX2Fycm93X2RuYV9kbmFbLCJzb3VyY2Vfbm9kZSJdKXsNCiAgeHl6PXJiaW5kKHh5eix0ZV9kNl9kbmFfbW9kdWxlX2FjcCR4W3Jvd25hbWVzKHRlX2Q2X2RuYV9tb2R1bGVfYWNwJHgpPT1pLGMoMTozKV0pICANCn0NCg0KDQoNCnh5el9lbmQ9TlVMTA0KZm9yIChpIGluIHRlXzNkX2Fycm93X2RuYV9kbmFbLCJ0YXJnZXRfbm9kZSJdKXsNCiAgeHl6X2VuZD1yYmluZCh4eXpfZW5kLHRlX2Q2X2RuYV9tb2R1bGVfYWNwJHhbcm93bmFtZXModGVfZDZfZG5hX21vZHVsZV9hY3AkeCk9PWksYygxOjMpXSkgIA0KfQ0KDQp0ZV9kbmFfZG5hXzNkX2Fycm93cz1kYXRhLmZyYW1lKHRlXzNkX2Fycm93X2RuYV9kbmEseF8zZF9hcnJvdz14eXpbLDFdLHlfM2RfYXJyb3c9eHl6WywyXSwgel8zZF9hcnJvdz14eXpbLDNdLHhlbmRfM2RfYXJyb3c9eHl6X2VuZFssMV0seWVuZF8zZF9hcnJvdz14eXpfZW5kWywyXSx6ZW5kXzNkX2Fycm93PXh5el9lbmRbLDNdKQ0KDQoNCg0KDQoNCg0KZXBpX2Q2X21vZHVsZV8zZF9hcnJvd3M9TlVMTA0KDQogIA0KZXBpXzNkX2Fycm93X3JuYV9ybmE9ZXBpX2Q2X2ludGVyYWN0aW9uX2RmW2VwaV9kNl9pbnRlcmFjdGlvbl9kZlssInNvdXJjZV9ub2RlIl0laW4lbW9kdWxlX3RyYW5zY3JpcHRzX2VwaV9kNiAmIGVwaV9kNl9pbnRlcmFjdGlvbl9kZlssInRhcmdldF9ub2RlIl0laW4lbW9kdWxlX3RyYW5zY3JpcHRzX2VwaV9kNixjKCJzb3VyY2Vfbm9kZSIsInRhcmdldF9ub2RlIildDQoNCnh5ej1OVUxMDQpmb3IgKGkgaW4gZXBpXzNkX2Fycm93X3JuYV9ybmFbLCJzb3VyY2Vfbm9kZSJdKXsNCiAgeHl6PXJiaW5kKHh5eixlcGlfZDZfcm5hX21vZHVsZV9hY3AkeFtyb3duYW1lcyhlcGlfZDZfcm5hX21vZHVsZV9hY3AkeCk9PWksYygxOjMpXSs1KSAgDQp9DQoNCg0KDQp4eXpfZW5kPU5VTEwNCmZvciAoaSBpbiBlcGlfM2RfYXJyb3dfcm5hX3JuYVssInRhcmdldF9ub2RlIl0pew0KICB4eXpfZW5kPXJiaW5kKHh5el9lbmQsZXBpX2Q2X3JuYV9tb2R1bGVfYWNwJHhbcm93bmFtZXMoZXBpX2Q2X3JuYV9tb2R1bGVfYWNwJHgpPT1pLGMoMTozKV0rNSkgIA0KfQ0KDQplcGlfcm5hX3JuYV8zZF9hcnJvd3M9ZGF0YS5mcmFtZShlcGlfM2RfYXJyb3dfcm5hX3JuYSx4XzNkX2Fycm93PXh5elssMV0seV8zZF9hcnJvdz14eXpbLDJdLCB6XzNkX2Fycm93PXh5elssM10seGVuZF8zZF9hcnJvdz14eXpfZW5kWywxXSx5ZW5kXzNkX2Fycm93PXh5el9lbmRbLDJdLHplbmRfM2RfYXJyb3c9eHl6X2VuZFssM10pDQoNCg0KDQoNCg0KcGVfZDhfbW9kdWxlXzNkX2Fycm93cz1OVUxMDQoNCiAgDQpwZV8zZF9hcnJvd19ybmFfcm5hPXBlX2Q4X2ludGVyYWN0aW9uX2RmW3BlX2Q4X2ludGVyYWN0aW9uX2RmWywic291cmNlX25vZGUiXSVpbiVtb2R1bGVfdHJhbnNjcmlwdHNfcGVfZDggJiBwZV9kOF9pbnRlcmFjdGlvbl9kZlssInRhcmdldF9ub2RlIl0laW4lbW9kdWxlX3RyYW5zY3JpcHRzX3BlX2Q4LGMoInNvdXJjZV9ub2RlIiwidGFyZ2V0X25vZGUiKV0NCg0KeHl6PU5VTEwNCmZvciAoaSBpbiBwZV8zZF9hcnJvd19ybmFfcm5hWywic291cmNlX25vZGUiXSl7DQogIHh5ej1yYmluZCh4eXoscGVfZDhfcm5hX21vZHVsZV9hY3AkeFtyb3duYW1lcyhwZV9kOF9ybmFfbW9kdWxlX2FjcCR4KT09aSxjKDE6MyldKzUpICANCn0NCg0KDQoNCnh5el9lbmQ9TlVMTA0KZm9yIChpIGluIHBlXzNkX2Fycm93X3JuYV9ybmFbLCJ0YXJnZXRfbm9kZSJdKXsNCiAgeHl6X2VuZD1yYmluZCh4eXpfZW5kLHBlX2Q4X3JuYV9tb2R1bGVfYWNwJHhbcm93bmFtZXMocGVfZDhfcm5hX21vZHVsZV9hY3AkeCk9PWksYygxOjMpXSs1KSAgDQp9DQoNCnBlX3JuYV9ybmFfM2RfYXJyb3dzPWRhdGEuZnJhbWUocGVfM2RfYXJyb3dfcm5hX3JuYSx4XzNkX2Fycm93PXh5elssMV0seV8zZF9hcnJvdz14eXpbLDJdLCB6XzNkX2Fycm93PXh5elssM10seGVuZF8zZF9hcnJvdz14eXpfZW5kWywxXSx5ZW5kXzNkX2Fycm93PXh5el9lbmRbLDJdLHplbmRfM2RfYXJyb3c9eHl6X2VuZFssM10pDQoNCg0KDQoNCg0KdGVfZDZfbW9kdWxlXzNkX2Fycm93cz1OVUxMDQoNCiAgDQp0ZV8zZF9hcnJvd19ybmFfcm5hPXRlX2Q2X2ludGVyYWN0aW9uX2RmW3RlX2Q2X2ludGVyYWN0aW9uX2RmWywic291cmNlX25vZGUiXSVpbiVtb2R1bGVfdHJhbnNjcmlwdHNfdGVfZDYgJiB0ZV9kNl9pbnRlcmFjdGlvbl9kZlssInRhcmdldF9ub2RlIl0laW4lbW9kdWxlX3RyYW5zY3JpcHRzX3RlX2Q2LGMoInNvdXJjZV9ub2RlIiwidGFyZ2V0X25vZGUiKV0NCg0KeHl6PU5VTEwNCmZvciAoaSBpbiB0ZV8zZF9hcnJvd19ybmFfcm5hWywic291cmNlX25vZGUiXSl7DQogIHh5ej1yYmluZCh4eXosdGVfZDZfcm5hX21vZHVsZV9hY3AkeFtyb3duYW1lcyh0ZV9kNl9ybmFfbW9kdWxlX2FjcCR4KT09aSxjKDE6MyldKzUpICANCn0NCg0KDQoNCnh5el9lbmQ9TlVMTA0KZm9yIChpIGluIHRlXzNkX2Fycm93X3JuYV9ybmFbLCJ0YXJnZXRfbm9kZSJdKXsNCiAgeHl6X2VuZD1yYmluZCh4eXpfZW5kLHRlX2Q2X3JuYV9tb2R1bGVfYWNwJHhbcm93bmFtZXModGVfZDZfcm5hX21vZHVsZV9hY3AkeCk9PWksYygxOjMpXSs1KSAgDQp9DQoNCnRlX3JuYV9ybmFfM2RfYXJyb3dzPWRhdGEuZnJhbWUodGVfM2RfYXJyb3dfcm5hX3JuYSx4XzNkX2Fycm93PXh5elssMV0seV8zZF9hcnJvdz14eXpbLDJdLCB6XzNkX2Fycm93PXh5elssM10seGVuZF8zZF9hcnJvdz14eXpfZW5kWywxXSx5ZW5kXzNkX2Fycm93PXh5el9lbmRbLDJdLHplbmRfM2RfYXJyb3c9eHl6X2VuZFssM10pDQoNCg0KDQoNCg0KDQoNCg0KDQplcGlfZDZfbW9kdWxlXzNkX2Fycm93cz1OVUxMDQoNCiAgDQplcGlfM2RfYXJyb3dfZG5hX3JuYT1lcGlfZDZfaW50ZXJhY3Rpb25fZGZbZXBpX2Q2X2ludGVyYWN0aW9uX2RmWywic291cmNlX25vZGUiXSVpbiVtb2R1bGVfcHJvbW90ZXJzX2VwaV9kNiAmIGVwaV9kNl9pbnRlcmFjdGlvbl9kZlssInRhcmdldF9ub2RlIl0laW4lbW9kdWxlX3RyYW5zY3JpcHRzX2VwaV9kNixjKCJzb3VyY2Vfbm9kZSIsInRhcmdldF9ub2RlIildDQoNCnh5ej1OVUxMDQpmb3IgKGkgaW4gZXBpXzNkX2Fycm93X2RuYV9ybmFbLCJzb3VyY2Vfbm9kZSJdKXsNCiAgeHl6PXJiaW5kKHh5eixlcGlfZDZfZG5hX21vZHVsZV9hY3AkeFtyb3duYW1lcyhlcGlfZDZfZG5hX21vZHVsZV9hY3AkeCk9PWksYygxOjMpXSkgIA0KfQ0KDQoNCg0KeHl6X2VuZD1OVUxMDQpmb3IgKGkgaW4gZXBpXzNkX2Fycm93X2RuYV9ybmFbLCJ0YXJnZXRfbm9kZSJdKXsNCiAgeHl6X2VuZD1yYmluZCh4eXpfZW5kLGVwaV9kNl9ybmFfbW9kdWxlX2FjcCR4W3Jvd25hbWVzKGVwaV9kNl9ybmFfbW9kdWxlX2FjcCR4KT09aSxjKDE6MyldKzUpICANCn0NCg0KZXBpX2RuYV9ybmFfM2RfYXJyb3dzPWRhdGEuZnJhbWUoZXBpXzNkX2Fycm93X2RuYV9ybmEseF8zZF9hcnJvdz14eXpbLDFdLHlfM2RfYXJyb3c9eHl6WywyXSwgel8zZF9hcnJvdz14eXpbLDNdLHhlbmRfM2RfYXJyb3c9eHl6X2VuZFssMV0seWVuZF8zZF9hcnJvdz14eXpfZW5kWywyXSx6ZW5kXzNkX2Fycm93PXh5el9lbmRbLDNdKQ0KDQoNCg0KDQoNCnBlX2Q4X21vZHVsZV8zZF9hcnJvd3M9TlVMTA0KDQogIA0KcGVfM2RfYXJyb3dfZG5hX3JuYT1wZV9kOF9pbnRlcmFjdGlvbl9kZltwZV9kOF9pbnRlcmFjdGlvbl9kZlssInNvdXJjZV9ub2RlIl0laW4lbW9kdWxlX3Byb21vdGVyc19wZV9kOCAmIHBlX2Q4X2ludGVyYWN0aW9uX2RmWywidGFyZ2V0X25vZGUiXSVpbiVtb2R1bGVfdHJhbnNjcmlwdHNfcGVfZDgsYygic291cmNlX25vZGUiLCJ0YXJnZXRfbm9kZSIpXQ0KDQp4eXo9TlVMTA0KZm9yIChpIGluIHBlXzNkX2Fycm93X2RuYV9ybmFbLCJzb3VyY2Vfbm9kZSJdKXsNCiAgeHl6PXJiaW5kKHh5eixwZV9kOF9kbmFfbW9kdWxlX2FjcCR4W3Jvd25hbWVzKHBlX2Q4X2RuYV9tb2R1bGVfYWNwJHgpPT1pLGMoMTozKV0pICANCn0NCg0KDQoNCnh5el9lbmQ9TlVMTA0KZm9yIChpIGluIHBlXzNkX2Fycm93X2RuYV9ybmFbLCJ0YXJnZXRfbm9kZSJdKXsNCiAgeHl6X2VuZD1yYmluZCh4eXpfZW5kLHBlX2Q4X3JuYV9tb2R1bGVfYWNwJHhbcm93bmFtZXMocGVfZDhfcm5hX21vZHVsZV9hY3AkeCk9PWksYygxOjMpXSs1KSAgDQp9DQoNCnBlX2RuYV9ybmFfM2RfYXJyb3dzPWRhdGEuZnJhbWUocGVfM2RfYXJyb3dfZG5hX3JuYSx4XzNkX2Fycm93PXh5elssMV0seV8zZF9hcnJvdz14eXpbLDJdLCB6XzNkX2Fycm93PXh5elssM10seGVuZF8zZF9hcnJvdz14eXpfZW5kWywxXSx5ZW5kXzNkX2Fycm93PXh5el9lbmRbLDJdLHplbmRfM2RfYXJyb3c9eHl6X2VuZFssM10pDQoNCg0KDQoNCg0KdGVfZDZfbW9kdWxlXzNkX2Fycm93cz1OVUxMDQoNCiAgDQp0ZV8zZF9hcnJvd19kbmFfcm5hPXRlX2Q2X2ludGVyYWN0aW9uX2RmW3RlX2Q2X2ludGVyYWN0aW9uX2RmWywic291cmNlX25vZGUiXSVpbiVtb2R1bGVfcHJvbW90ZXJzX3RlX2Q2ICYgdGVfZDZfaW50ZXJhY3Rpb25fZGZbLCJ0YXJnZXRfbm9kZSJdJWluJW1vZHVsZV90cmFuc2NyaXB0c190ZV9kNixjKCJzb3VyY2Vfbm9kZSIsInRhcmdldF9ub2RlIildDQoNCnh5ej1OVUxMDQpmb3IgKGkgaW4gdGVfM2RfYXJyb3dfZG5hX3JuYVssInNvdXJjZV9ub2RlIl0pew0KICB4eXo9cmJpbmQoeHl6LHRlX2Q2X2RuYV9tb2R1bGVfYWNwJHhbcm93bmFtZXModGVfZDZfZG5hX21vZHVsZV9hY3AkeCk9PWksYygxOjMpXSkgIA0KfQ0KDQoNCg0KeHl6X2VuZD1OVUxMDQpmb3IgKGkgaW4gdGVfM2RfYXJyb3dfZG5hX3JuYVssInRhcmdldF9ub2RlIl0pew0KICB4eXpfZW5kPXJiaW5kKHh5el9lbmQsdGVfZDZfcm5hX21vZHVsZV9hY3AkeFtyb3duYW1lcyh0ZV9kNl9ybmFfbW9kdWxlX2FjcCR4KT09aSxjKDE6MyldKzUpICANCn0NCg0KdGVfZG5hX3JuYV8zZF9hcnJvd3M9ZGF0YS5mcmFtZSh0ZV8zZF9hcnJvd19kbmFfcm5hLHhfM2RfYXJyb3c9eHl6WywxXSx5XzNkX2Fycm93PXh5elssMl0sIHpfM2RfYXJyb3c9eHl6WywzXSx4ZW5kXzNkX2Fycm93PXh5el9lbmRbLDFdLHllbmRfM2RfYXJyb3c9eHl6X2VuZFssMl0semVuZF8zZF9hcnJvdz14eXpfZW5kWywzXSkNCg0KDQoNCg0KDQoNCmVwaV9kNl9tb2R1bGVfM2RfYXJyb3dzPU5VTEwNCg0KICANCmVwaV8zZF9hcnJvd19ybmFfZG5hPWVwaV9kNl9pbnRlcmFjdGlvbl9kZltlcGlfZDZfaW50ZXJhY3Rpb25fZGZbLCJzb3VyY2Vfbm9kZSJdJWluJW1vZHVsZV90cmFuc2NyaXB0c19lcGlfZDYgJiBlcGlfZDZfaW50ZXJhY3Rpb25fZGZbLCJ0YXJnZXRfbm9kZSJdJWluJW1vZHVsZV9wcm9tb3RlcnNfZXBpX2Q2LGMoInNvdXJjZV9ub2RlIiwidGFyZ2V0X25vZGUiKV0NCg0KeHl6PU5VTEwNCmZvciAoaSBpbiBlcGlfM2RfYXJyb3dfcm5hX2RuYVssInNvdXJjZV9ub2RlIl0pew0KICB4eXo9cmJpbmQoeHl6LGVwaV9kNl9ybmFfbW9kdWxlX2FjcCR4W3Jvd25hbWVzKGVwaV9kNl9ybmFfbW9kdWxlX2FjcCR4KT09aSxjKDE6MyldKzUpICANCn0NCg0KDQoNCnh5el9lbmQ9TlVMTA0KZm9yIChpIGluIGVwaV8zZF9hcnJvd19ybmFfZG5hWywidGFyZ2V0X25vZGUiXSl7DQogIHh5el9lbmQ9cmJpbmQoeHl6X2VuZCxlcGlfZDZfZG5hX21vZHVsZV9hY3AkeFtyb3duYW1lcyhlcGlfZDZfZG5hX21vZHVsZV9hY3AkeCk9PWksYygxOjMpXSkgIA0KfQ0KDQplcGlfcm5hX2RuYV8zZF9hcnJvd3M9ZGF0YS5mcmFtZShlcGlfM2RfYXJyb3dfcm5hX2RuYSx4XzNkX2Fycm93PXh5elssMV0seV8zZF9hcnJvdz14eXpbLDJdLCB6XzNkX2Fycm93PXh5elssM10seGVuZF8zZF9hcnJvdz14eXpfZW5kWywxXSx5ZW5kXzNkX2Fycm93PXh5el9lbmRbLDJdLHplbmRfM2RfYXJyb3c9eHl6X2VuZFssM10pDQoNCg0KDQoNCg0KcGVfZDhfbW9kdWxlXzNkX2Fycm93cz1OVUxMDQoNCiAgDQpwZV8zZF9hcnJvd19ybmFfZG5hPXBlX2Q4X2ludGVyYWN0aW9uX2RmW3BlX2Q4X2ludGVyYWN0aW9uX2RmWywic291cmNlX25vZGUiXSVpbiVtb2R1bGVfdHJhbnNjcmlwdHNfcGVfZDggJiBwZV9kOF9pbnRlcmFjdGlvbl9kZlssInRhcmdldF9ub2RlIl0laW4lbW9kdWxlX3Byb21vdGVyc19wZV9kOCxjKCJzb3VyY2Vfbm9kZSIsInRhcmdldF9ub2RlIildDQoNCnh5ej1OVUxMDQpmb3IgKGkgaW4gcGVfM2RfYXJyb3dfcm5hX2RuYVssInNvdXJjZV9ub2RlIl0pew0KICB4eXo9cmJpbmQoeHl6LHBlX2Q4X3JuYV9tb2R1bGVfYWNwJHhbcm93bmFtZXMocGVfZDhfcm5hX21vZHVsZV9hY3AkeCk9PWksYygxOjMpXSs1KSAgDQp9DQoNCg0KDQp4eXpfZW5kPU5VTEwNCmZvciAoaSBpbiBwZV8zZF9hcnJvd19ybmFfZG5hWywidGFyZ2V0X25vZGUiXSl7DQogIHh5el9lbmQ9cmJpbmQoeHl6X2VuZCxwZV9kOF9kbmFfbW9kdWxlX2FjcCR4W3Jvd25hbWVzKHBlX2Q4X2RuYV9tb2R1bGVfYWNwJHgpPT1pLGMoMTozKV0pICANCn0NCg0KcGVfcm5hX2RuYV8zZF9hcnJvd3M9ZGF0YS5mcmFtZShwZV8zZF9hcnJvd19ybmFfZG5hLHhfM2RfYXJyb3c9eHl6WywxXSx5XzNkX2Fycm93PXh5elssMl0sIHpfM2RfYXJyb3c9eHl6WywzXSx4ZW5kXzNkX2Fycm93PXh5el9lbmRbLDFdLHllbmRfM2RfYXJyb3c9eHl6X2VuZFssMl0semVuZF8zZF9hcnJvdz14eXpfZW5kWywzXSkNCg0KDQoNCg0KDQp0ZV9kNl9tb2R1bGVfM2RfYXJyb3dzPU5VTEwNCg0KICANCnRlXzNkX2Fycm93X3JuYV9kbmE9dGVfZDZfaW50ZXJhY3Rpb25fZGZbdGVfZDZfaW50ZXJhY3Rpb25fZGZbLCJzb3VyY2Vfbm9kZSJdJWluJW1vZHVsZV90cmFuc2NyaXB0c190ZV9kNiAmIHRlX2Q2X2ludGVyYWN0aW9uX2RmWywidGFyZ2V0X25vZGUiXSVpbiVtb2R1bGVfcHJvbW90ZXJzX3RlX2Q2LGMoInNvdXJjZV9ub2RlIiwidGFyZ2V0X25vZGUiKV0NCg0KeHl6PU5VTEwNCmZvciAoaSBpbiB0ZV8zZF9hcnJvd19ybmFfZG5hWywic291cmNlX25vZGUiXSl7DQogIHh5ej1yYmluZCh4eXosdGVfZDZfcm5hX21vZHVsZV9hY3AkeFtyb3duYW1lcyh0ZV9kNl9ybmFfbW9kdWxlX2FjcCR4KT09aSxjKDE6MyldKzUpICANCn0NCg0KDQoNCnh5el9lbmQ9TlVMTA0KZm9yIChpIGluIHRlXzNkX2Fycm93X3JuYV9kbmFbLCJ0YXJnZXRfbm9kZSJdKXsNCiAgeHl6X2VuZD1yYmluZCh4eXpfZW5kLHRlX2Q2X2RuYV9tb2R1bGVfYWNwJHhbcm93bmFtZXModGVfZDZfZG5hX21vZHVsZV9hY3AkeCk9PWksYygxOjMpXSkgIA0KfQ0KDQp0ZV9ybmFfZG5hXzNkX2Fycm93cz1kYXRhLmZyYW1lKHRlXzNkX2Fycm93X3JuYV9kbmEseF8zZF9hcnJvdz14eXpbLDFdLHlfM2RfYXJyb3c9eHl6WywyXSwgel8zZF9hcnJvdz14eXpbLDNdLHhlbmRfM2RfYXJyb3c9eHl6X2VuZFssMV0seWVuZF8zZF9hcnJvdz14eXpfZW5kWywyXSx6ZW5kXzNkX2Fycm93PXh5el9lbmRbLDNdKQ0KDQplcGlfZDZfM2RfYXJyb3dzPXJiaW5kKGVwaV9kbmFfZG5hXzNkX2Fycm93cywgZXBpX2RuYV9ybmFfM2RfYXJyb3dzLCBlcGlfcm5hX3JuYV8zZF9hcnJvd3MsIGVwaV9ybmFfZG5hXzNkX2Fycm93cykNCnBlX2Q4XzNkX2Fycm93cz1yYmluZChwZV9kbmFfZG5hXzNkX2Fycm93cywgcGVfZG5hX3JuYV8zZF9hcnJvd3MsIHBlX3JuYV9ybmFfM2RfYXJyb3dzLCBwZV9ybmFfZG5hXzNkX2Fycm93cykNCnRlX2Q2XzNkX2Fycm93cz1yYmluZCh0ZV9kbmFfZG5hXzNkX2Fycm93cywgdGVfZG5hX3JuYV8zZF9hcnJvd3MsIHRlX3JuYV9ybmFfM2RfYXJyb3dzLCB0ZV9ybmFfZG5hXzNkX2Fycm93cykNCg0KYGBgYA0KDQoNCg0KYGBgYHtyIDNkIG5ldHdvcmtzIHdnY25hIG1vZHVsZSBwYWlyc30NCg0KZXBpX2Q2X21vZHVsZV9hY3A9cmJpbmQoZXBpX2Q2X2RuYV9tb2R1bGVfYWNwJHhbLGMoMTozKV0sIGVwaV9kNl9ybmFfbW9kdWxlX2FjcCR4WyxjKDE6MyldKzUpDQplcGlfZDZfc2l6ZT1jKGVwaV9kNl9kbmFfc2l6ZSxlcGlfZDZfcm5hX3NpemUpDQoNCnNjZW5lID0gbGlzdCgNCiAgeGF4aXMgPSBsaXN0KA0KICB0aXRsZSA9ICIiLA0KICB6ZXJvbGluZSA9IEZBTFNFLA0KICBzaG93bGluZSA9IEZBTFNFLA0KICBzaG93dGlja2xhYmVscyA9IEZBTFNFLA0KICBzaG93Z3JpZCA9IEZBTFNFDQopLA0KICB5YXhpcyA9IGxpc3QoDQogIHRpdGxlID0gIiIsDQogIHplcm9saW5lID0gRkFMU0UsDQogIHNob3dsaW5lID0gRkFMU0UsDQogIHNob3d0aWNrbGFiZWxzID0gRkFMU0UsDQogIHNob3dncmlkID0gRkFMU0UNCiksDQogIHpheGlzID0gbGlzdCgNCiAgdGl0bGUgPSAiIiwNCiAgemVyb2xpbmUgPSBGQUxTRSwNCiAgc2hvd2xpbmUgPSBGQUxTRSwNCiAgc2hvd3RpY2tsYWJlbHMgPSBGQUxTRSwNCiAgc2hvd2dyaWQgPSBGQUxTRQ0KKSkNCg0KDQplcGlfZDZfbW9kdWxlX2FjcF9maWcgPC0gcGxvdF9seSh4PWVwaV9kNl9tb2R1bGVfYWNwWywiUEMxIl0sIHk9ZXBpX2Q2X21vZHVsZV9hY3BbLCJQQzIiXSwgej1lcGlfZDZfbW9kdWxlX2FjcFssIlBDMyJdDQosYWxwaGE9MC41LA0Kc2l6ZSA9IH5sb2coZXBpX2Q2X3NpemUrMSwxMCksIG1hcmtlciA9IGxpc3Qoc3ltYm9sID0gJ2NpcmNsZScsIHNpemVtb2RlID0gJ2RpYW1ldGVyJyksIHNpemVzID0gYygxMywxMjApLGNvbG9yPX5jKHJlcCgiZG5hIixsZW5ndGgobW9kdWxlX3Byb21vdGVyc19lcGlfZDYpKSxyZXAoInJuYSIsbGVuZ3RoKG1vZHVsZV90cmFuc2NyaXB0c19lcGlfZDYpKSksY29sb3JzPWMoImdyZWVuIiwicHVycGxlIikNCikgICU+JSBhZGRfbWFya2VycygNCiAgICAgICAgICAgICAgdGV4dCA9IHJvd25hbWVzKGVwaV9kNl9tb2R1bGVfYWNwKSwNCiAgICAgICAgICAgICAgdGV4dGZvbnQgPSBsaXN0KHNpemU9bG9nMihlcGlfZDZfc2l6ZSsxLjUpKjE1LCBjb2xvcj0gYyhyZXAoImdyZWVuIixsZW5ndGgobW9kdWxlX3Byb21vdGVyc19lcGlfZDYpKSxyZXAoInB1cnBsZSIsbGVuZ3RoKG1vZHVsZV90cmFuc2NyaXB0c19lcGlfZDYpKSkpLA0KICAgICAgICAgICAgICBzaG93bGVnZW5kID0gVCklPiVsYXlvdXQoc2NlbmU9c2NlbmUpIA0KDQplcGlfZDZfbW9kdWxlX2Fycm93X2ZpZz1OVUxMDQoNCmZvciAoaSBpbiBzZXEobnJvdyhyYmluZChlcGlfZG5hX2RuYV8zZF9hcnJvd3MsZXBpX2RuYV9ybmFfM2RfYXJyb3dzKSkpKXsNCnBsb3RfbHkoKSAlPiUNCiAgYWRkX3RyYWNlKHggPSBjKGVwaV9kNl8zZF9hcnJvd3MkeF8zZF9hcnJvd1tpXSxlcGlfZDZfM2RfYXJyb3dzJHhlbmRfM2RfYXJyb3dbaV0pLA0KICAgIHkgPSBjKGVwaV9kNl8zZF9hcnJvd3MkeV8zZF9hcnJvd1tpXSxlcGlfZDZfM2RfYXJyb3dzJHllbmRfM2RfYXJyb3dbaV0pLA0KICAgIHogPSBjKGVwaV9kNl8zZF9hcnJvd3Mkel8zZF9hcnJvd1tpXSxlcGlfZDZfM2RfYXJyb3dzJHplbmRfM2RfYXJyb3dbaV0pLA0KICAgIHR5cGUgPSAic2NhdHRlcjNkIiwgbW9kZSA9ICJsaW5lcyIsIG5hbWUgPSAibGluZXMiLCBzaG93bGVnZW5kID0gRkFMU0UsDQogICAgbGluZT1saXN0KGNvbG9yPSJncmVlbiIsIHdpZHRoID0gMSwgYWxwaGE9MC4xKSkgLT4gZXBpX2Q2X21vZHVsZV9hcnJvd19maWdbW2ldXQ0KfQ0KDQoNCmZvciAoaSBpbiBzZXEobnJvdyhyYmluZChlcGlfZG5hX2RuYV8zZF9hcnJvd3MsZXBpX2RuYV9ybmFfM2RfYXJyb3dzKSksKG5yb3cocmJpbmQoZXBpX2RuYV9kbmFfM2RfYXJyb3dzLGVwaV9kbmFfcm5hXzNkX2Fycm93cykpK25yb3cocmJpbmQoZXBpX3JuYV9ybmFfM2RfYXJyb3dzLGVwaV9ybmFfZG5hXzNkX2Fycm93cykpKSkpew0KcGxvdF9seSgpICU+JQ0KICBhZGRfdHJhY2UoeCA9IGMoZXBpX2Q2XzNkX2Fycm93cyR4XzNkX2Fycm93W2ldLGVwaV9kNl8zZF9hcnJvd3MkeGVuZF8zZF9hcnJvd1tpXSksDQogICAgeSA9IGMoZXBpX2Q2XzNkX2Fycm93cyR5XzNkX2Fycm93W2ldLGVwaV9kNl8zZF9hcnJvd3MkeWVuZF8zZF9hcnJvd1tpXSksDQogICAgeiA9IGMoZXBpX2Q2XzNkX2Fycm93cyR6XzNkX2Fycm93W2ldLGVwaV9kNl8zZF9hcnJvd3MkemVuZF8zZF9hcnJvd1tpXSksDQogICAgdHlwZSA9ICJzY2F0dGVyM2QiLCBtb2RlID0gImxpbmVzIiwgbmFtZSA9ICJsaW5lcyIsIHNob3dsZWdlbmQgPSBGQUxTRSwNCiAgICBsaW5lPWxpc3QoY29sb3I9InB1cnBsZSIsIHdpZHRoID0gMSwgYWxwaGE9MC4xKSklPiVsYXlvdXQoc2NlbmU9c2NlbmUpIC0+IGVwaV9kNl9tb2R1bGVfYXJyb3dfZmlnW1tpXV0NCn0NCg0KZXBpX2Q2X21vZHVsZV9hcnJvd19maWckbm9kZXM9ZXBpX2Q2X21vZHVsZV9hY3BfZmlnDQoNCnN1YnBsb3QoZXBpX2Q2X21vZHVsZV9hcnJvd19maWcpDQoNCg0KcGVfZDhfbW9kdWxlX2FjcD1yYmluZChwZV9kOF9kbmFfbW9kdWxlX2FjcCR4WyxjKDE6MyldLCBwZV9kOF9ybmFfbW9kdWxlX2FjcCR4WyxjKDE6MyldKzUpDQpwZV9kOF9zaXplPWMocGVfZDhfZG5hX3NpemUscGVfZDhfcm5hX3NpemUpDQoNCnNjZW5lID0gbGlzdCgNCiAgeGF4aXMgPSBsaXN0KA0KICB0aXRsZSA9ICIiLA0KICB6ZXJvbGluZSA9IEZBTFNFLA0KICBzaG93bGluZSA9IEZBTFNFLA0KICBzaG93dGlja2xhYmVscyA9IEZBTFNFLA0KICBzaG93Z3JpZCA9IEZBTFNFDQopLA0KICB5YXhpcyA9IGxpc3QoDQogIHRpdGxlID0gIiIsDQogIHplcm9saW5lID0gRkFMU0UsDQogIHNob3dsaW5lID0gRkFMU0UsDQogIHNob3d0aWNrbGFiZWxzID0gRkFMU0UsDQogIHNob3dncmlkID0gRkFMU0UNCiksDQogIHpheGlzID0gbGlzdCgNCiAgdGl0bGUgPSAiIiwNCiAgemVyb2xpbmUgPSBGQUxTRSwNCiAgc2hvd2xpbmUgPSBGQUxTRSwNCiAgc2hvd3RpY2tsYWJlbHMgPSBGQUxTRSwNCiAgc2hvd2dyaWQgPSBGQUxTRQ0KKSkNCg0KDQpwZV9kOF9tb2R1bGVfYWNwX2ZpZyA8LSBwbG90X2x5KHg9cGVfZDhfbW9kdWxlX2FjcFssIlBDMSJdLCB5PXBlX2Q4X21vZHVsZV9hY3BbLCJQQzIiXSwgej1wZV9kOF9tb2R1bGVfYWNwWywiUEMzIl0NCixhbHBoYT0wLjUsDQpzaXplID0gfmxvZyhwZV9kOF9zaXplKzEsMTApLCBtYXJrZXIgPSBsaXN0KHN5bWJvbCA9ICdjaXJjbGUnLCBzaXplbW9kZSA9ICdkaWFtZXRlcicpLCBzaXplcyA9IGMoMTMsMTIwKSxjb2xvcj1+YyhyZXAoImRuYSIsbGVuZ3RoKG1vZHVsZV9wcm9tb3RlcnNfcGVfZDgpKSxyZXAoInJuYSIsbGVuZ3RoKG1vZHVsZV90cmFuc2NyaXB0c19wZV9kOCkpKSxjb2xvcnM9YygiZ3JlZW4iLCJwdXJwbGUiKQ0KKSAgJT4lIGFkZF9tYXJrZXJzKA0KICAgICAgICAgICAgICB0ZXh0ID0gcm93bmFtZXMocGVfZDhfbW9kdWxlX2FjcCksDQogICAgICAgICAgICAgIHRleHRmb250ID0gbGlzdChzaXplPWxvZzIocGVfZDhfc2l6ZSsxLjUpKjE1LCBjb2xvcj0gYyhyZXAoImdyZWVuIixsZW5ndGgobW9kdWxlX3Byb21vdGVyc19wZV9kOCkpLHJlcCgicHVycGxlIixsZW5ndGgobW9kdWxlX3RyYW5zY3JpcHRzX3BlX2Q4KSkpKSwNCiAgICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IFQpJT4lbGF5b3V0KHNjZW5lPXNjZW5lKSANCg0KcGVfZDhfbW9kdWxlX2Fycm93X2ZpZz1OVUxMDQoNCmZvciAoaSBpbiBzZXEobnJvdyhyYmluZChwZV9kbmFfZG5hXzNkX2Fycm93cyxwZV9kbmFfcm5hXzNkX2Fycm93cykpKSl7DQpwbG90X2x5KCkgJT4lDQogIGFkZF90cmFjZSh4ID0gYyhwZV9kOF8zZF9hcnJvd3MkeF8zZF9hcnJvd1tpXSxwZV9kOF8zZF9hcnJvd3MkeGVuZF8zZF9hcnJvd1tpXSksDQogICAgeSA9IGMocGVfZDhfM2RfYXJyb3dzJHlfM2RfYXJyb3dbaV0scGVfZDhfM2RfYXJyb3dzJHllbmRfM2RfYXJyb3dbaV0pLA0KICAgIHogPSBjKHBlX2Q4XzNkX2Fycm93cyR6XzNkX2Fycm93W2ldLHBlX2Q4XzNkX2Fycm93cyR6ZW5kXzNkX2Fycm93W2ldKSwNCiAgICB0eXBlID0gInNjYXR0ZXIzZCIsIG1vZGUgPSAibGluZXMiLCBuYW1lID0gImxpbmVzIiwgc2hvd2xlZ2VuZCA9IEZBTFNFLA0KICAgIGxpbmU9bGlzdChjb2xvcj0iZ3JlZW4iLCB3aWR0aCA9IDEsIGFscGhhPTAuMSkpIC0+IHBlX2Q4X21vZHVsZV9hcnJvd19maWdbW2ldXQ0KfQ0KDQoNCmZvciAoaSBpbiBzZXEobnJvdyhyYmluZChwZV9kbmFfZG5hXzNkX2Fycm93cyxwZV9kbmFfcm5hXzNkX2Fycm93cykpLChucm93KHJiaW5kKHBlX2RuYV9kbmFfM2RfYXJyb3dzLHBlX2RuYV9ybmFfM2RfYXJyb3dzKSkrbnJvdyhyYmluZChwZV9ybmFfcm5hXzNkX2Fycm93cyxwZV9ybmFfZG5hXzNkX2Fycm93cykpKSkpew0KcGxvdF9seSgpICU+JQ0KICBhZGRfdHJhY2UoeCA9IGMocGVfZDhfM2RfYXJyb3dzJHhfM2RfYXJyb3dbaV0scGVfZDhfM2RfYXJyb3dzJHhlbmRfM2RfYXJyb3dbaV0pLA0KICAgIHkgPSBjKHBlX2Q4XzNkX2Fycm93cyR5XzNkX2Fycm93W2ldLHBlX2Q4XzNkX2Fycm93cyR5ZW5kXzNkX2Fycm93W2ldKSwNCiAgICB6ID0gYyhwZV9kOF8zZF9hcnJvd3Mkel8zZF9hcnJvd1tpXSxwZV9kOF8zZF9hcnJvd3MkemVuZF8zZF9hcnJvd1tpXSksDQogICAgdHlwZSA9ICJzY2F0dGVyM2QiLCBtb2RlID0gImxpbmVzIiwgbmFtZSA9ICJsaW5lcyIsIHNob3dsZWdlbmQgPSBGQUxTRSwNCiAgICBsaW5lPWxpc3QoY29sb3I9InB1cnBsZSIsIHdpZHRoID0gMSwgYWxwaGE9MC4xKSklPiVsYXlvdXQoc2NlbmU9c2NlbmUpIC0+IHBlX2Q4X21vZHVsZV9hcnJvd19maWdbW2ldXQ0KfQ0KDQpwZV9kOF9tb2R1bGVfYXJyb3dfZmlnJG5vZGVzPXBlX2Q4X21vZHVsZV9hY3BfZmlnDQoNCnN1YnBsb3QocGVfZDhfbW9kdWxlX2Fycm93X2ZpZykNCg0KDQoNCnRlX2Q2X21vZHVsZV9hY3A9cmJpbmQodGVfZDZfZG5hX21vZHVsZV9hY3AkeFssYygxOjMpXSwgdGVfZDZfcm5hX21vZHVsZV9hY3AkeFssYygxOjMpXSs1KQ0KdGVfZDZfc2l6ZT1jKHRlX2Q2X2RuYV9zaXplLHRlX2Q2X3JuYV9zaXplKQ0KDQpzY2VuZSA9IGxpc3QoDQogIHhheGlzID0gbGlzdCgNCiAgdGl0bGUgPSAiIiwNCiAgemVyb2xpbmUgPSBGQUxTRSwNCiAgc2hvd2xpbmUgPSBGQUxTRSwNCiAgc2hvd3RpY2tsYWJlbHMgPSBGQUxTRSwNCiAgc2hvd2dyaWQgPSBGQUxTRQ0KKSwNCiAgeWF4aXMgPSBsaXN0KA0KICB0aXRsZSA9ICIiLA0KICB6ZXJvbGluZSA9IEZBTFNFLA0KICBzaG93bGluZSA9IEZBTFNFLA0KICBzaG93dGlja2xhYmVscyA9IEZBTFNFLA0KICBzaG93Z3JpZCA9IEZBTFNFDQopLA0KICB6YXhpcyA9IGxpc3QoDQogIHRpdGxlID0gIiIsDQogIHplcm9saW5lID0gRkFMU0UsDQogIHNob3dsaW5lID0gRkFMU0UsDQogIHNob3d0aWNrbGFiZWxzID0gRkFMU0UsDQogIHNob3dncmlkID0gRkFMU0UNCikpDQoNCg0KdGVfZDZfbW9kdWxlX2FjcF9maWcgPC0gcGxvdF9seSh4PXRlX2Q2X21vZHVsZV9hY3BbLCJQQzEiXSwgeT10ZV9kNl9tb2R1bGVfYWNwWywiUEMyIl0sIHo9dGVfZDZfbW9kdWxlX2FjcFssIlBDMyJdDQosYWxwaGE9MC41LA0Kc2l6ZSA9IH5sb2codGVfZDZfc2l6ZSsxLDEwKSwgbWFya2VyID0gbGlzdChzeW1ib2wgPSAnY2lyY2xlJywgc2l6ZW1vZGUgPSAnZGlhbWV0ZXInKSwgc2l6ZXMgPSBjKDEzLDEyMCksY29sb3I9fmMocmVwKCJkbmEiLGxlbmd0aChtb2R1bGVfcHJvbW90ZXJzX3RlX2Q2KSkscmVwKCJybmEiLGxlbmd0aChtb2R1bGVfdHJhbnNjcmlwdHNfdGVfZDYpKSksY29sb3JzPWMoImdyZWVuIiwicHVycGxlIikNCikgICU+JSBhZGRfbWFya2VycygNCiAgICAgICAgICAgICAgdGV4dCA9IHJvd25hbWVzKHRlX2Q2X21vZHVsZV9hY3ApLA0KICAgICAgICAgICAgICB0ZXh0Zm9udCA9IGxpc3Qoc2l6ZT1sb2cyKHRlX2Q2X3NpemUrMS41KSoxNSwgY29sb3I9IGMocmVwKCJncmVlbiIsbGVuZ3RoKG1vZHVsZV9wcm9tb3RlcnNfdGVfZDYpKSxyZXAoInB1cnBsZSIsbGVuZ3RoKG1vZHVsZV90cmFuc2NyaXB0c190ZV9kNikpKSksDQogICAgICAgICAgICAgIHNob3dsZWdlbmQgPSBUKSU+JWxheW91dChzY2VuZT1zY2VuZSkgDQoNCnRlX2Q2X21vZHVsZV9hcnJvd19maWc9TlVMTA0KDQpmb3IgKGkgaW4gc2VxKG5yb3cocmJpbmQodGVfZG5hX2RuYV8zZF9hcnJvd3MsdGVfZG5hX3JuYV8zZF9hcnJvd3MpKSkpew0KcGxvdF9seSgpICU+JQ0KICBhZGRfdHJhY2UoeCA9IGModGVfZDZfM2RfYXJyb3dzJHhfM2RfYXJyb3dbaV0sdGVfZDZfM2RfYXJyb3dzJHhlbmRfM2RfYXJyb3dbaV0pLA0KICAgIHkgPSBjKHRlX2Q2XzNkX2Fycm93cyR5XzNkX2Fycm93W2ldLHRlX2Q2XzNkX2Fycm93cyR5ZW5kXzNkX2Fycm93W2ldKSwNCiAgICB6ID0gYyh0ZV9kNl8zZF9hcnJvd3Mkel8zZF9hcnJvd1tpXSx0ZV9kNl8zZF9hcnJvd3MkemVuZF8zZF9hcnJvd1tpXSksDQogICAgdHlwZSA9ICJzY2F0dGVyM2QiLCBtb2RlID0gImxpbmVzIiwgbmFtZSA9ICJsaW5lcyIsIHNob3dsZWdlbmQgPSBGQUxTRSwNCiAgICBsaW5lPWxpc3QoY29sb3I9ImdyZWVuIiwgd2lkdGggPSAxLCBhbHBoYT0wLjEpKSAtPiB0ZV9kNl9tb2R1bGVfYXJyb3dfZmlnW1tpXV0NCn0NCg0KDQpmb3IgKGkgaW4gc2VxKG5yb3cocmJpbmQodGVfZG5hX2RuYV8zZF9hcnJvd3MsdGVfZG5hX3JuYV8zZF9hcnJvd3MpKSwobnJvdyhyYmluZCh0ZV9kbmFfZG5hXzNkX2Fycm93cyx0ZV9kbmFfcm5hXzNkX2Fycm93cykpK25yb3cocmJpbmQodGVfcm5hX3JuYV8zZF9hcnJvd3MsdGVfcm5hX2RuYV8zZF9hcnJvd3MpKSkpKXsNCnBsb3RfbHkoKSAlPiUNCiAgYWRkX3RyYWNlKHggPSBjKHRlX2Q2XzNkX2Fycm93cyR4XzNkX2Fycm93W2ldLHRlX2Q2XzNkX2Fycm93cyR4ZW5kXzNkX2Fycm93W2ldKSwNCiAgICB5ID0gYyh0ZV9kNl8zZF9hcnJvd3MkeV8zZF9hcnJvd1tpXSx0ZV9kNl8zZF9hcnJvd3MkeWVuZF8zZF9hcnJvd1tpXSksDQogICAgeiA9IGModGVfZDZfM2RfYXJyb3dzJHpfM2RfYXJyb3dbaV0sdGVfZDZfM2RfYXJyb3dzJHplbmRfM2RfYXJyb3dbaV0pLA0KICAgIHR5cGUgPSAic2NhdHRlcjNkIiwgbW9kZSA9ICJsaW5lcyIsIG5hbWUgPSAibGluZXMiLCBzaG93bGVnZW5kID0gRkFMU0UsDQogICAgbGluZT1saXN0KGNvbG9yPSJwdXJwbGUiLCB3aWR0aCA9IDEsIGFscGhhPTAuMSkpJT4lbGF5b3V0KHNjZW5lPXNjZW5lKSAtPiB0ZV9kNl9tb2R1bGVfYXJyb3dfZmlnW1tpXV0NCn0NCg0KdGVfZDZfbW9kdWxlX2Fycm93X2ZpZyRub2Rlcz10ZV9kNl9tb2R1bGVfYWNwX2ZpZw0KDQpzdWJwbG90KHRlX2Q2X21vZHVsZV9hcnJvd19maWcpDQoNCg0KDQpgYGBgDQoNCg0KIyMgTWl4LUtlcm5lbCBhbmFseXNpcw0KDQoNCldlIHdhbnQgbm93IHRvIGdvIGZ1cnRoZXIgYW5kIHVzZSBhIGtlcm5lbCBiYXNlZCBhcHByb2FjaCwgd2hpY2ggY29tcHV0ZXMgYSBtdWx0aS1kaW1lbnNpb24gc3BhY2UgaW4gd2hpY2ggZW1icnlvIGNlbGxzIHdpbGwgcGxhY2UgZ2l2ZW4gdGhlaXIgdmljaW5pdHkgYWNyb3NzIGdlbmUgcHJvbW90ZXIgbWV0aHlsYXRpb24gYW5kIGdlbmUgZXhwcmVzc2lvbi4gVGhpcyBleHBsb3JhdG9yeSBub24tc3VwZXJ2aXNlZCBhbmFseXNpcyB0cmFjZXMgYSBub24tbGluZWFyIGZyb250aWVyIG9mIGRlY2lzaW9uIHRoYXQgYWxsb2NhdGVzIGluZGl2aWR1YWxzIGludG8gZ3JvdXBzIChbTWFyaWV0dGUgYW5kIFZpYWxhbmVpeCwgMjAxOF0oI21hcmlldHRlXzIwMTgpKS4NCg0KYGBgYHtyIG1peGtlcm5lbCBmYV9wZmEsIGVjaG89RkFMU0V9DQpkbmFfcm5hX21peF9rZXJuZWw9bGlzdChsb2cyKGRuYV91cG1fc3Vic2V0KzEpLCBsb2cyKHJuYV9zdWJzZXQrMSlbLGNvbG5hbWVzKGRuYV91cG1fc3Vic2V0KV0pDQpuYW1lcyhkbmFfcm5hX21peF9rZXJuZWwpPWMoImRuYSIsInJuYSIpDQoNCg0KIyBjb21wdXRlIGtlcm5lbA0KZG5hX2tlcm5lbCA8LSBjb21wdXRlLmtlcm5lbCh0KGRuYV9ybmFfbWl4X2tlcm5lbCRkbmEpLCBrZXJuZWwuZnVuYyA9ICJsaW5lYXIiKQ0Kcm5hX2tlcm5lbCA8LSBjb21wdXRlLmtlcm5lbCh0KGRuYV9ybmFfbWl4X2tlcm5lbCRybmEpLCBrZXJuZWwuZnVuYyA9ICJsaW5lYXIiKQ0KDQojIGNoZWNrIGRpbWVuc2lvbnMNCmRpbShkbmFfa2VybmVsJGtlcm5lbCkNCmRpbShybmFfa2VybmVsJGtlcm5lbCkNCg0KYGBgYA0KDQpgYGBge3IgbWl4IGtlcm5lbCBleHBsYWluZWQgdmFyaWFuY2UsIG91dC53aWR0aD0iOTAlIiwgZmlnLnRvcGNhcHRpb24gPSBUUlVFICwgZmlnLmNhcD0iPGNlbnRlcj4qKlZhcmlhbmNlIGV4cGxhaW5lZCBieSBrZXJuZWwgZm9yIHRoZSB0d28gZGF0YXNldHMqKjwvY2VudGVyPiJ9DQoNCmNpbS5rZXJuZWwoZG5hID0gZG5hX2tlcm5lbCwNCiAgICAgICAgICAgcm5hID0gcm5hX2tlcm5lbCwNCiAgICAgICAgICAgbWV0aG9kID0gInNxdWFyZSINCikNCg0Kcm5hX2RuYV9tZXRhX2tlcm5lbCA8LSBjb21iaW5lLmtlcm5lbHMoZG5hID0gZG5hX2tlcm5lbCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBybmEgPSBybmFfa2VybmVsLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gImZ1bGwtVU1LTCIpDQoNCmtlcm5lbC5wY2EucmVzdWx0IDwtIGtlcm5lbC5wY2Eocm5hX2RuYV9tZXRhX2tlcm5lbCwgbmNvbXAgPSAxMCkNCg0KIyBzYXZlLmltYWdlKCIyMDIxXzA2XzA5X2VtYnJ5b19rZXJuZWwiKQ0KbG9hZCgiMjAyMV8wNl8wOV9lbWJyeW9fa2VybmVsIikNCmBgYGANCg0KV2UgbmVlZGVkIGEgc3BhY2Ugd2l0aGluIGNlbGxzIHNlZ3JlZ2F0ZSBieSBkZXZlbG9wbWVudGFsIHN0YWdlIGFuZCBsaW5lYWdlIHByb2dyZXNzaW9uIC0+IGtlcm5lbCBhbG1vc3Qgc3VjY2VlZGVkLg0KSW5kZWVkLCBjb250cmFyeSB0byBzaW5nbGUgUENBIG9yIFVNQVAsIGtlcm5lbCByZWNhcGl0dWxhdGVzIGJvdGggZGV2ZWxvcG1lbnRhbCBzdGFnZSBwcm9ncmVzc2lvbiBhbmQgbGluZWFnZSBzcGVjaWZpY2F0aW9uLg0KDQpXZSBjYW4gdXNlIHRoaXMga2VybmVsIHNwYWNlIHRvIHZpc3VhbGl6ZSBtZXRoeWxhdGlvbiBhbmQgZXhwcmVzc2lvbiBvZiBnZW5lcywgbm90YWJseSBXR0NOQSBtb2R1bGUgZ2VuZXMsIHRocm91Z2hvdXQgZWFybHkgZGV2ZWxvcG1lbnQgb2YgdGhlIGh1bWFuIGVtYnJ5by4NCg0KYGBgYHtyIHIgbWl4a2VybmVsIGZhX3BmYSAzZCwgZmlndXJlcy1zaWRlLCBmaWcuc2hvdz0iaG9sZCIsIG91dC53aWR0aD0iOTAlIiwgZmlnLnRvcGNhcHRpb24gPSBUUlVFICwgZmlnLmNhcD0iPGNlbnRlcj4qKjNEIEtlcm5lbCBQQ0EgKEtQQ0EpKio8L2NlbnRlcj4ifQ0KbGluZWFnZV9rZXJuZWw9bGluZWFnZVtyb3duYW1lcyhrZXJuZWwucGNhLnJlc3VsdCR4KV0NCm5leHQzZCgpDQpzY2VuZV9rZXJuZWwgPSBsaXN0KGNhbWVyYSA9IGxpc3QoZXllID0gbGlzdCh4ID0gMCwgeSA9IDAsIHogPSAxLjI1KSkpDQpmaWcgPC0gcGxvdF9seSh4PWtlcm5lbC5wY2EucmVzdWx0JHhbLDFdLHk9a2VybmVsLnBjYS5yZXN1bHQkeFssMl0sej1rZXJuZWwucGNhLnJlc3VsdCR4WywzXSxjb2xvciA9IH5mYWN0b3IobGluZWFnZV9rZXJuZWwsbGV2ZWxzPWMoIkVwaSIsICJQRSIsICJURSIpKSwgY29sb3JzID0gYygicmVkIiwiZ3JlZW4iLCJibHVlIiksYWxwaGE9MC42KQ0KZmlnIDwtIGZpZyAlPiUgYWRkX21hcmtlcnMoKQ0KZmlnDQoNCmRheV9rZXJuZWw9ZGF5W3Jvd25hbWVzKGtlcm5lbC5wY2EucmVzdWx0JHgpXQ0KbmV4dDNkKCkNCnNjZW5lX2tlcm5lbCA9IGxpc3QoY2FtZXJhID0gbGlzdChleWUgPSBsaXN0KHggPSAwLCB5ID0gMCwgeiA9IDEuMjUpKSkNCmZpZyA8LSBwbG90X2x5KHg9a2VybmVsLnBjYS5yZXN1bHQkeFssMV0seT1rZXJuZWwucGNhLnJlc3VsdCR4WywyXSx6PWtlcm5lbC5wY2EucmVzdWx0JHhbLDNdLGNvbG9yID0gfmZhY3RvcihkYXlfa2VybmVsLGxldmVscz1jKCJENiIsICJEOCIsICJEMTAiLCAiRDEyIikpLCBjb2xvcnMgPSBjKCJ5ZWxsb3ciLCJ0dXJxdW9pc2UiLCJwdXJwbGUiLCJyZWQiKSxhbHBoYT0wLjYpDQpmaWcgPC0gZmlnICU+JSBhZGRfbWFya2VycygpDQpmaWcNCg0KDQpwcm9tb3Rlcl9rZXJuZWw9bG9nMihkbmFfdXBtX3N1YnNldFt3aGljaChyb3duYW1lcyhkbmFfdXBtX3N1YnNldCk9PSJQT1U1RjEiKSxdKzEpDQpuZXh0M2QoKQ0Kc2NlbmVfa2VybmVsID0gbGlzdChjYW1lcmEgPSBsaXN0KGV5ZSA9IGxpc3QoeCA9IDAsIHkgPSAwLCB6ID0gMS4yNSkpKQ0KZmlnIDwtIHBsb3RfbHkoeD1rZXJuZWwucGNhLnJlc3VsdCR4WywxXSx5PWtlcm5lbC5wY2EucmVzdWx0JHhbLDJdLHo9a2VybmVsLnBjYS5yZXN1bHQkeFssM10sY29sb3IgPSB+cHJvbW90ZXJfa2VybmVsLGFscGhhPTEsIGNvbG9ycz1jKCJibHVlIiwibGlnaHRibHVlIiwiI0ZGQzBDQiIsInJlZCIpKQ0KZmlnIDwtIGZpZyAlPiUgYWRkX21hcmtlcnMoKQ0KZmlnDQoNCnRyYW5zY3JpcHRfa2VybmVsPWxvZzIocm5hX3N1YnNldFt3aGljaChyb3duYW1lcyhybmFfc3Vic2V0KT09IlBPVTVGMSIpLF0rMSkNCm5leHQzZCgpDQpzY2VuZV9rZXJuZWwgPSBsaXN0KGNhbWVyYSA9IGxpc3QoZXllID0gbGlzdCh4ID0gMCwgeSA9IDAsIHogPSAxLjI1KSkpDQpmaWcgPC0gcGxvdF9seSh4PWtlcm5lbC5wY2EucmVzdWx0JHhbLDFdLHk9a2VybmVsLnBjYS5yZXN1bHQkeFssMl0sej1rZXJuZWwucGNhLnJlc3VsdCR4WywzXSxjb2xvciA9IH50cmFuc2NyaXB0X2tlcm5lbCxhbHBoYT0xLCBjb2xvcnM9YygiYmx1ZSIsImxpZ2h0Ymx1ZSIsIiNGRkMwQ0IiLCJyZWQiKSkNCmZpZyA8LSBmaWcgJT4lIGFkZF9tYXJrZXJzKCkNCmZpZw0KDQp0ZXJmMV9ybmFfYm94cGxvdD1kYXRhLmZyYW1lKG1ldGFkYXRhLGV4cHI9bG9nMihybmFfc3Vic2V0W3doaWNoKHJvd25hbWVzKHJuYV9zdWJzZXQpPT0iVEVSRjEiKSxdKzEpLGxpbmVhZ2VfZGF5PXBhc3RlMChtZXRhZGF0YSRsaW5lYWdlLCJfIixtZXRhZGF0YSRkYXkpKQ0KDQoNCnRlcmYxX3JuYV9ib3hwbG90JGxpbmVhZ2VfZGF5PWZhY3Rvcih0ZXJmMV9ybmFfYm94cGxvdCRsaW5lYWdlX2RheSxsZXZlbHM9YygiRXBpX0Q2IiwgIkVwaV9EOCIsICJFcGlfRDEwIiwgIlBFX0Q2IiwgIlBFX0Q4IiwgIlBFX0QxMCIsICJQRV9EMTIiLCAiVEVfRDYiLCAiVEVfRDgiLCAiVEVfRDEwIiwgIlRFX0QxMiIpKQ0KDQpnZ3Bsb3QodGVyZjFfcm5hX2JveHBsb3QsYWVzKHg9bGluZWFnZV9kYXkseT1leHByLGZpbGw9bGluZWFnZV9kYXkpKSsNCiAgZ2VvbV9ib3hwbG90KCkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjZmY2ZWViIiwiI2YwMWRiZCIsIiNmMDFkOGQiLCIjNWRmNzAwIiwiIzIwY2MyZCIsIiMxMGFlNGEiLCIjMzlhNDU1IiwiIzA0ZjFmYyIsIiMyMGMxZTEiLCJibHVlIiwiZGFya2JsdWUiKSkrDQogIGxhYnModGl0bGU9IlRFUkYxIGdlbmUgZXhwcmVzc2lvbiIpDQoNCkNIRUsyX2RuYV9ib3hwbG90PWRhdGEuZnJhbWUobWV0YWRhdGEsZXhwcj1sb2cyKGRuYV91cG1fc3Vic2V0W3doaWNoKHJvd25hbWVzKGRuYV91cG1fc3Vic2V0KT09IkNIRUsyIiksXSsxKSxsaW5lYWdlX2RheT1wYXN0ZTAobWV0YWRhdGEkbGluZWFnZSwiXyIsbWV0YWRhdGEkZGF5KSkNCg0KQ0hFSzJfZG5hX2JveHBsb3QkbGluZWFnZV9kYXk9ZmFjdG9yKENIRUsyX2RuYV9ib3hwbG90JGxpbmVhZ2VfZGF5LGxldmVscz1jKCJFcGlfRDYiLCAiRXBpX0Q4IiwgIkVwaV9EMTAiLCAiUEVfRDYiLCAiUEVfRDgiLCAiUEVfRDEwIiwgIlBFX0QxMiIsICJURV9ENiIsICJURV9EOCIsICJURV9EMTAiLCAiVEVfRDEyIikpDQoNCmdncGxvdChDSEVLMl9kbmFfYm94cGxvdCxhZXMoeD1saW5lYWdlX2RheSx5PWV4cHIsZmlsbD1saW5lYWdlX2RheSkpKw0KICBnZW9tX2JveHBsb3QoKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIiNmZjZlZWIiLCIjZjAxZGJkIiwiI2YwMWQ4ZCIsIiM1ZGY3MDAiLCIjMjBjYzJkIiwiIzEwYWU0YSIsIiMzOWE0NTUiLCIjMDRmMWZjIiwiIzIwYzFlMSIsImJsdWUiLCJkYXJrYmx1ZSIpKSsNCiAgbGFicyh0aXRsZT0iQ0hFSzIgRE5BIG1ldGh5bGF0aW9uIikNCg0KQ0hFSzJfcm5hX2JveHBsb3Q9ZGF0YS5mcmFtZShtZXRhZGF0YSxleHByPWxvZzIocm5hX3N1YnNldFt3aGljaChyb3duYW1lcyhybmFfc3Vic2V0KT09IkNIRUsyIiksXSsxKSxsaW5lYWdlX2RheT1wYXN0ZTAobWV0YWRhdGEkbGluZWFnZSwiXyIsbWV0YWRhdGEkZGF5KSkNCg0KQ0hFSzJfcm5hX2JveHBsb3QkbGluZWFnZV9kYXk9ZmFjdG9yKENIRUsyX3JuYV9ib3hwbG90JGxpbmVhZ2VfZGF5LGxldmVscz1jKCJFcGlfRDYiLCAiRXBpX0Q4IiwgIkVwaV9EMTAiLCAiUEVfRDYiLCAiUEVfRDgiLCAiUEVfRDEwIiwgIlBFX0QxMiIsICJURV9ENiIsICJURV9EOCIsICJURV9EMTAiLCAiVEVfRDEyIikpDQoNCmdncGxvdChDSEVLMl9ybmFfYm94cGxvdCxhZXMoeD1saW5lYWdlX2RheSx5PWV4cHIsZmlsbD1saW5lYWdlX2RheSkpKw0KICBnZW9tX2JveHBsb3QoKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIiNmZjZlZWIiLCIjZjAxZGJkIiwiI2YwMWQ4ZCIsIiM1ZGY3MDAiLCIjMjBjYzJkIiwiIzEwYWU0YSIsIiMzOWE0NTUiLCIjMDRmMWZjIiwiIzIwYzFlMSIsImJsdWUiLCJkYXJrYmx1ZSIpKSsNCiAgbGFicyh0aXRsZT0iQ0hFSzIgZ2VuZSBleHByZXNzaW9uIikNCg0KDQoNCmBgYGANCg0KYGBgYHtyIGtlcm5lbCBwbG90IHBjYSByZXMsIGZpZ3VyZXMtc2lkZSwgZmlnLnNob3c9ImhvbGQiLCBvdXQud2lkdGg9IjUwJSIsIGZpZy50b3BjYXB0aW9uID0gVFJVRSAsIGZpZy5jYXA9IjxjZW50ZXI+KipWYXJpYW5jZSBleHBsYWluZWQgYnkgUEMgb2YgS1BDQSoqPC9jZW50ZXI+In0NCnBsb3Qoa2VybmVsLnBjYS5yZXN1bHQpDQpgYGBgDQoNCkNsZWFybHksIHRoZSBrZXJuZWwgUENBIChLUENBKSBzaG93cyBhIHNwYWNlIGluIHdoaWNoIGVtYnJ5b25pYyBjZWxsIHZpY2luaXR5IHJlY2FwaXR1bGF0ZXMgYm90aCBsaW5lYWdlcyBhbmQgZGV2ZWxvcG1lbnRhbCBkYXkuIFRoaXMgaXMgb2YgdXRtb3N0IGludGVyZXN0IGFzIHdlIGNvdWxkIG5vdCBjb21iaW5lIHRoZXNlIHR3byB0cmFpdHMgd2l0aCBzdWZmaWNpZW50IHJlc29sdXRpb24uDQoNClRoZXJlZm9yZSwgdGhlIGtlcm5lbCBiYXNlZCBhcHByb2FjaCBpbnRlZ3JhdGVzIGdlbmUgcHJvbW90ZXIgbWV0aHlsYXRpb24gd2l0aCBnZW5lIGV4cHJlc3Npb24gYW5kIGNvbXB1dGVzIGEgc3BhY2UgcmVjYXBpdHVsYXRpbmcgZGV2ZWxvcG1lbnRhbCBwcm9ncmVzc2lvbiBhbmQgbGluZWFnZSBzcGVjaWZpY2F0aW9uIG9mIHRoZSBlYXJseSBodW1hbiBlbWJyeW8uDQoNCg0KIyBQRVJTUEVDVElWRSA6IE1hY2hpbmUgbGVhcm5pbmcgLT4gYWxnb3JpdGhtIHRoYXQgY2FuIGFzc2lnbiByb2J1c3RseSBjZWxsIGxpbmVhZ2VzIGFuZCBkZXZlbG9wbWVudGFsIHRpbWUNCldlIGNhbiB1c2UgdGhpcyBtb2RlbCB0byBidWlsZCBhbiBhbGdvcml0aG0gdGhhdCBhc3NpZ24gYSBnaXZlbiBlbWJyeW8gY2VsbCB0byBsaW5lYWdlIGFuZCBkZXZlbG9wbWVudGFsIHN0YWdlLCBwcm92aWRlZCBETkEgbWV0aHlsYXRpb24gYW5kIGdlbmUgZXhwcmVzc2lvbiBtZWFzdXJlcy4NCg0KTWFjaGluZSBsZWFybmluZyBtb2RlbDoNCg0KLSBjcmVhdGUNCi0gdHJhaW4NCi0gdGVzdCAob24gb3RoZXIgZGF0YXNldHMgdG9vLCBzaG91bGQgd29yayBmb3Igc2luZ2xlIGRhdGFzZXQgYW5kIGJvdGggZGF0YXNldCBpbnB1dCkNCi0gdXNlDQoNCkEgcHJlZGljdGl2ZSBtb2RlbCBjb3VsZCBoZWxwIHRvIHJlc29sdmUgaW50ZXItZW1icnlvIGRldmVsb3BtZW50YWwgZGVsYXlzIG9yIG1pc2xlYWRlZCBhbm5vdGF0aW9uLCBhbmQgdGh1cyBhY2N1cmF0ZSBkZXZlbG9wbWVudGFsIHN0YWdlIGFuZCBsaW5lYWdlIG1hdHVyYXRpb24gaWRlbnRpZmljYXRpb24uIFRoaXMgYWxzbyBjb3VsZCBoZWxwIHRvIHVuaWZ5IHRoZSBkaXZlcnNlIGRhdGFzZXRzIG9uIGEgY29tbW9uIGFubm90YXRpb24sIHRodXMgaGVscGluZyB0byBjb21wYXJlIHRoZXNlIGRhdGEuDQoNCkZvciB0aGlzIHB1cnBvc2UsIHdlIGNvdWxkIHN1YnNldCB0aGUgY3VycmVudCBkYXRhc2V0IGFuZCB1c2UgdGhlIGtlcm5lbCBzcGFjZSBhbmQgdGhlIFdHQ05BIG1vZHVsZXMsIHRvIHRyYWluIHRoZSBtb2RlbCBvbiBvbmUgc2V0IG9mIGNlbGxzLCBhbmQgdGVzdCBpdCBvbiB0aGUgb3RoZXIgc2V0LCBib3RoIG9mIHdoaWNoIHJlcHJlc2VudGF0aXZlIG9mIGRldmVsb3BtZW50YWwgZGF5IGFuZCBsaW5lYWdlIGRpc3RyaWJ1dGlvbi4NCg0KSG93ZXZlciwgaXQgd291bGQgYmUgYmV0dGVyIHRoYXQgb25jZSBuZXcgZGF0YXNldHMgYXJlIHByb2R1Y2VkLCB3ZSB0ZXN0IG91ciBtb2RlbCBvbiB0aGVzZS4NCg0KIyBEaWZmaWN1bHRpZXMNCg0KLSBubyBhY2Nlc3MgdG8gZmFzdHEgZmlsZXMNCi0gZGlmZmljdWx0aWVzIHRvIG5vcm1hbGlzZSBkYXRhIHByb3Blcmx5DQotIHJlc3VsdHMgc3Ryb25nbHkgZGVwZW5kIG9uIGlucHV0IGRhdGEgZGlzdHJpYnV0aW9uDQotIGhhcmQgdG8gc2VsZWN0IGFwcHJvcHJpYXRlIHNvZnQtcG93ZXIgdGhyZXNob2xkIGZvciBXR0NOQQ0KLSBmdW5jdGlvbmFsIGVucmljaG1lbnQgZGF0YWJhc2VzIHNlZW0gaW5hY2N1cmF0ZSBmb3IgdGhlIGh1bWFuIGVtYnJ5bw0KDQojIFNlc3Npb24gaW5mbw0KDQpgYGB7ciBzZXNzaW9uX2luZm99DQoNCnNlc3Npb25JbmZvKCkNCg0KYGBgDQoNCiMgUmVmZXJlbmNlcw0KDQojIyMjIyMgQXJnZWxhZ3VldCwgUi4sIFZlbHRlbiwgQi4sIEFybm9sLCBELiwgRGlldHJpY2gsIFMuLCBaZW56LCBULiwgTWFyaW9uaSwgSi4gQy4sIEJ1ZXR0bmVyLCBGLiwgSHViZXIsIFcuLCAmIFN0ZWdsZSwgTy4gKDIwMTgpLiBNdWx0aS1PbWljcyBGYWN0b3IgQW5hbHlzaXMtYSBmcmFtZXdvcmsgZm9yIHVuc3VwZXJ2aXNlZCBpbnRlZ3JhdGlvbiBvZiBtdWx0aS1vbWljcyBkYXRhIHNldHMuIE1vbGVjdWxhciBzeXN0ZW1zIGJpb2xvZ3ksIDE0KDYpLCBlODEyNC4gW2h0dHBzOi8vZG9pLm9yZy8xMC4xNTI1Mi9tc2IuMjAxNzgxMjRdKGh0dHBzOi8vZG9pLm9yZy8xMC4xNTI1Mi9tc2IuMjAxNzgxMjQpIHsjYXJnZWxhZ3VldF8yMDE4fQ0KDQojIyMjIyMgSmFza293aWFrLCBQLiBBLiwgQ2FtcGVsbG8sIFIuIEouLCAmIENvc3RhLCBJLiBHLiAoMjAxNCkuIE9uIHRoZSBzZWxlY3Rpb24gb2YgYXBwcm9wcmlhdGUgZGlzdGFuY2VzIGZvciBnZW5lIGV4cHJlc3Npb24gZGF0YSBjbHVzdGVyaW5nLiBCTUMgYmlvaW5mb3JtYXRpY3MsIDE1IFN1cHBsIDIoU3VwcGwgMiksIFMyLiBbaHR0cHM6Ly9kb2kub3JnLzEwLjExODYvMTQ3MS0yMTA1LTE1LVMyLVMyXShodHRwczovL2RvaS5vcmcvMTAuMTE4Ni8xNDcxLTIxMDUtMTUtUzItUzIpIHsjamFza293aWFrXzIwMTR9DQoNCg0KIyMjIyMjIEtvYmFrLCBELiwgTGluZGVybWFuLCBHLkMuIEluaXRpYWxpemF0aW9uIGlzIGNyaXRpY2FsIGZvciBwcmVzZXJ2aW5nIGdsb2JhbCBkYXRhIHN0cnVjdHVyZSBpbiBib3RoIHQtU05FIGFuZCBVTUFQLiBOYXQgQmlvdGVjaG5vbCAzOSwgMTU24oCTMTU3ICgyMDIxKS4gW2h0dHBzOi8vZG9pLW9yZy5wcm94eS5pbnNlcm1iaWJsaW8uaW5pc3QuZnIvMTAuMTAzOC9zNDE1ODctMDIwLTAwODA5LXpdKGh0dHBzOi8vZG9pLW9yZy5wcm94eS5pbnNlcm1iaWJsaW8uaW5pc3QuZnIvMTAuMTAzOC9zNDE1ODctMDIwLTAwODA5LXopIHsja29iYWtfMjAyMX0NCg0KIyMjIyMjIExhbmdmZWxkZXIsIFAuLCBIb3J2YXRoLCBTLiBXR0NOQTogYW4gUiBwYWNrYWdlIGZvciB3ZWlnaHRlZCBjb3JyZWxhdGlvbiBuZXR3b3JrIGFuYWx5c2lzLiBCTUMgQmlvaW5mb3JtYXRpY3MgOSwgNTU5ICgyMDA4KS4gW2h0dHBzOi8vZG9pLm9yZy8xMC4xMTg2LzE0NzEtMjEwNS05LTU1OV0oaHR0cHM6Ly9kb2kub3JnLzEwLjExODYvMTQ3MS0yMTA1LTktNTU5KSB7I2xhbmdmZWxkZXJfMjAwOH0NCg0KIyMjIyMjIExhd2xvciwgTi4sIEZhYmJyaSwgQS4sIEd1YW4sIFAuLCBHZW9yZ2UsIEouLCAmIEthcnV0dXJpLCBSLiBLLiAoMjAxNikuIG11bHRpQ2x1c3Q6IEFuIFItcGFja2FnZSBmb3IgSWRlbnRpZnlpbmcgQmlvbG9naWNhbGx5IFJlbGV2YW50IENsdXN0ZXJzIGluIENhbmNlciBUcmFuc2NyaXB0b21lIFByb2ZpbGVzLiBDYW5jZXIgaW5mb3JtYXRpY3MsIDE1LCAxMDPigJMxMTQuIFtodHRwczovL2RvaS5vcmcvMTAuNDEzNy9DSU4uUzM4MDAwXShodHRwczovL2RvaS5vcmcvMTAuNDEzNy9DSU4uUzM4MDAwKSB7I2xhd2xvcl8yMDE2fQ0KDQojIyMjIyMgTGV2ZXIsIEouLCBLcnp5d2luc2tpLCBNLiAmIEFsdG1hbiwgTi4gUHJpbmNpcGFsIGNvbXBvbmVudCBhbmFseXNpcy4gTmF0IE1ldGhvZHMgMTQsIDY0MeKAkzY0MiAoMjAxNykuIFtodHRwczovL2RvaS5vcmcvMTAuMTAzOC9ubWV0aC40MzQ2XShodHRwczovL2RvaS5vcmcvMTAuMTAzOC9ubWV0aC40MzQ2KSB7I2xldmVyXzIwMTd9DQoNCiMjIyMjIyBNYXJpZXR0ZSwgSi4sICYgVmlsbGEtVmlhbGFuZWl4LCBOLiAoMjAxOCkuIFVuc3VwZXJ2aXNlZCBtdWx0aXBsZSBrZXJuZWwgbGVhcm5pbmcgZm9yIGhldGVyb2dlbmVvdXMgZGF0YSBpbnRlZ3JhdGlvbi4gQmlvaW5mb3JtYXRpY3MgKE94Zm9yZCwgRW5nbGFuZCksIDM0KDYpLCAxMDA54oCTMTAxNS5baHR0cHM6Ly9kb2kub3JnLzEwLjEwOTMvYmlvaW5mb3JtYXRpY3MvYnR4NjgyXShodHRwczovL2RvaS5vcmcvMTAuMTA5My9iaW9pbmZvcm1hdGljcy9idHg2ODIpIHsjbWFyaWV0dGVfMjAxOH0NCg0KIyMjIyMjIE1vbMOoLCBNLiBBLiwgV2ViZXJsaW5nLCBBLiwgJiBaZXJuaWNrYS1Hb2V0eiwgTS4gKDIwMjApLiBDb21wYXJhdGl2ZSBhbmFseXNpcyBvZiBodW1hbiBhbmQgbW91c2UgZGV2ZWxvcG1lbnQ6IEZyb20genlnb3RlIHRvIHByZS1nYXN0cnVsYXRpb24uIEN1cnJlbnQgdG9waWNzIGluIGRldmVsb3BtZW50YWwgYmlvbG9neSwgMTM2LCAxMTPigJMxMzguIFtodHRwczovL2RvaS5vcmcvMTAuMTAxNi9icy5jdGRiLjIwMTkuMTAuMDAyXShodHRwczovL2RvaS5vcmcvMTAuMTAxNi9icy5jdGRiLjIwMTkuMTAuMDAyKSB7I21vbGVfMjAyMH0NCg0KIyMjIyMjIFpob3UsIEYuLCBXYW5nLCBSLiwgWXVhbiwgUC4sIFJlbiwgWS4sIE1hbywgWS4sIExpLCBSLiwgTGlhbiwgWS4sIExpLCBKLiwgV2VuLCBMLiwgWWFuLCBMLiwgUWlhbywgSi4sICYgVGFuZywgRi4gKDIwMTkpLiBSZWNvbnN0aXR1dGluZyB0aGUgdHJhbnNjcmlwdG9tZSBhbmQgRE5BIG1ldGh5bG9tZSBsYW5kc2NhcGVzIG9mIGh1bWFuIGltcGxhbnRhdGlvbi4gTmF0dXJlLCA1NzIoNzc3MSksIDY2MOKAkzY2NC4gW2h0dHBzOi8vZG9pLm9yZy8xMC4xMDM4L3M0MTU4Ni0wMTktMTUwMC0wXShodHRwczovL2RvaS5vcmcvMTAuMTAzOC9zNDE1ODYtMDE5LTE1MDAtMCkgeyN6aG91XzIwMTl9DQoNCiMjIyMjIyBab3BwaSwgSi4sIEd1aWxsYXVtZSwgSkYuLCBOZXVubGlzdCwgTS4gZXQgYWwuIE1pQmlPbWljczogYW4gaW50ZXJhY3RpdmUgd2ViIGFwcGxpY2F0aW9uIGZvciBtdWx0aS1vbWljcyBkYXRhIGV4cGxvcmF0aW9uIGFuZCBpbnRlZ3JhdGlvbi4gQk1DIEJpb2luZm9ybWF0aWNzIDIyLCA2ICgyMDIxKS4gW2h0dHBzOi8vZG9pLm9yZy8xMC4xMTg2L3MxMjg1OS0wMjAtMDM5MjEtOF0oaHR0cHM6Ly9kb2kub3JnLzEwLjExODYvczEyODU5LTAyMC0wMzkyMS04KSB7I3pvcHBpXzIwMjF9DQo=